From ef5ccd6c41237a870dd7242b72b006d6bd42cd07 Mon Sep 17 00:00:00 2001 From: John Marino Date: Sat, 5 Oct 2013 19:18:38 +0200 Subject: [PATCH] Upgrade GDB from 7.4.1 to 7.6.1 on the vendor branch --- contrib/gdb-7/bfd/README | 6 + contrib/gdb-7/bfd/archive.c | 543 +- contrib/gdb-7/bfd/archive64.c | 19 +- contrib/gdb-7/bfd/archures.c | 74 +- contrib/gdb-7/bfd/bfd-in.h | 72 +- contrib/gdb-7/bfd/bfd-in2.h | 783 +- contrib/gdb-7/bfd/bfd.c | 219 +- contrib/gdb-7/bfd/bfdio.c | 26 +- contrib/gdb-7/bfd/cache.c | 14 +- contrib/gdb-7/bfd/coffgen.c | 100 +- contrib/gdb-7/bfd/compress.c | 82 +- contrib/gdb-7/bfd/config.bfd | 141 +- contrib/gdb-7/bfd/corefile.c | 4 +- contrib/gdb-7/bfd/cpu-i386.c | 88 + contrib/gdb-7/bfd/cpu-l1om.c | 5 + contrib/gdb-7/bfd/dwarf2.c | 494 +- contrib/gdb-7/bfd/elf-attrs.c | 16 +- contrib/gdb-7/bfd/elf-bfd.h | 341 +- contrib/gdb-7/bfd/elf-eh-frame.c | 176 +- contrib/gdb-7/bfd/elf-ifunc.c | 8 +- contrib/gdb-7/bfd/elf-linux-psinfo.h | 127 + contrib/gdb-7/bfd/elf-nacl.c | 224 + .../gdb-7/{gdb/gdb_vfork.h => bfd/elf-nacl.h} | 20 +- contrib/gdb-7/bfd/elf-strtab.c | 28 +- contrib/gdb-7/bfd/elf-vxworks.c | 34 +- contrib/gdb-7/bfd/elf.c | 963 +- contrib/gdb-7/bfd/elf32-i386.c | 520 +- contrib/gdb-7/bfd/elf64-x86-64.c | 956 +- contrib/gdb-7/bfd/elfcode.h | 68 +- contrib/gdb-7/bfd/elfcore.h | 33 +- contrib/gdb-7/bfd/elflink.c | 1395 +- contrib/gdb-7/bfd/elfxx-target.h | 21 +- contrib/gdb-7/bfd/format.c | 212 +- contrib/gdb-7/bfd/hash.c | 4 +- contrib/gdb-7/bfd/libbfd.c | 13 + contrib/gdb-7/bfd/libbfd.h | 347 +- contrib/gdb-7/bfd/libcoff.h | 5 +- contrib/gdb-7/bfd/linker.c | 154 +- contrib/gdb-7/bfd/merge.c | 14 + contrib/gdb-7/bfd/opncls.c | 47 +- contrib/gdb-7/bfd/reloc.c | 902 +- contrib/gdb-7/bfd/section.c | 155 +- contrib/gdb-7/bfd/stab-syms.c | 3 +- contrib/gdb-7/bfd/syms.c | 7 +- contrib/gdb-7/bfd/sysdep.h | 4 + contrib/gdb-7/bfd/targets.c | 50 +- contrib/gdb-7/bfd/tekhex.c | 2 +- contrib/gdb-7/bfd/version.h | 2 +- contrib/gdb-7/gdb/README | 8 +- contrib/gdb-7/gdb/ada-exp.c | 3784 ++++ contrib/gdb-7/gdb/ada-exp.y | 73 +- contrib/gdb-7/gdb/ada-lang.c | 1236 +- contrib/gdb-7/gdb/ada-lang.h | 57 +- contrib/gdb-7/gdb/ada-lex.c | 2205 +- contrib/gdb-7/gdb/ada-operator.def | 3 +- contrib/gdb-7/gdb/ada-tasks.c | 144 +- contrib/gdb-7/gdb/ada-typeprint.c | 108 +- contrib/gdb-7/gdb/ada-valprint.c | 258 +- contrib/gdb-7/gdb/ada-varobj.c | 888 + contrib/gdb-7/gdb/ada-varobj.h | 55 + contrib/gdb-7/gdb/addrmap.c | 2 +- contrib/gdb-7/gdb/addrmap.h | 2 +- contrib/gdb-7/gdb/agent.c | 87 + contrib/gdb-7/gdb/amd64-nat.c | 8 +- contrib/gdb-7/gdb/amd64-nat.h | 2 +- contrib/gdb-7/gdb/amd64-tdep.c | 375 +- contrib/gdb-7/gdb/amd64-tdep.h | 7 +- contrib/gdb-7/gdb/amd64bsd-nat.c | 75 +- .../gdb/{gdb_select.h => amd64bsd-nat.h} | 29 +- contrib/gdb-7/gdb/annotate.c | 81 +- contrib/gdb-7/gdb/annotate.h | 8 +- contrib/gdb-7/gdb/arch-utils.c | 25 +- contrib/gdb-7/gdb/arch-utils.h | 10 +- contrib/gdb-7/gdb/auto-load.c | 1306 ++ contrib/gdb-7/gdb/auto-load.h | 61 + contrib/gdb-7/gdb/auxv.c | 20 +- contrib/gdb-7/gdb/auxv.h | 2 +- contrib/gdb-7/gdb/ax-gdb.c | 326 +- contrib/gdb-7/gdb/ax-gdb.h | 13 +- contrib/gdb-7/gdb/ax-general.c | 42 +- contrib/gdb-7/gdb/ax.h | 12 +- contrib/gdb-7/gdb/bcache.c | 3 +- contrib/gdb-7/gdb/bcache.h | 3 +- contrib/gdb-7/gdb/bfd-target.c | 6 +- contrib/gdb-7/gdb/bfd-target.h | 8 +- contrib/gdb-7/gdb/block.c | 407 +- contrib/gdb-7/gdb/block.h | 130 +- contrib/gdb-7/gdb/blockframe.c | 22 +- contrib/gdb-7/gdb/break-catch-sig.c | 507 + contrib/gdb-7/gdb/breakpoint.c | 4391 +++- contrib/gdb-7/gdb/breakpoint.h | 237 +- contrib/gdb-7/gdb/bsd-kvm.c | 2 +- contrib/gdb-7/gdb/bsd-kvm.h | 2 +- contrib/gdb-7/gdb/bsd-uthread.c | 18 +- contrib/gdb-7/gdb/bsd-uthread.h | 2 +- contrib/gdb-7/gdb/btrace.c | 543 + contrib/gdb-7/gdb/btrace.h | 142 + contrib/gdb-7/gdb/buildsym.c | 412 +- contrib/gdb-7/gdb/buildsym.h | 76 +- contrib/gdb-7/gdb/c-exp.y | 662 +- contrib/gdb-7/gdb/c-lang.c | 41 +- contrib/gdb-7/gdb/c-lang.h | 23 +- contrib/gdb-7/gdb/c-typeprint.c | 748 +- contrib/gdb-7/gdb/c-valprint.c | 390 +- contrib/gdb-7/gdb/call-cmds.h | 34 - contrib/gdb-7/gdb/cc-with-index.sh | 126 - contrib/gdb-7/gdb/charset-list.h | 2 +- contrib/gdb-7/gdb/charset.c | 42 +- contrib/gdb-7/gdb/charset.h | 2 +- contrib/gdb-7/gdb/cleanups.c | 293 + contrib/gdb-7/gdb/cleanups.h | 69 + contrib/gdb-7/gdb/cli-out.c | 6 +- contrib/gdb-7/gdb/cli-out.h | 2 +- contrib/gdb-7/gdb/cli/cli-cmds.c | 266 +- contrib/gdb-7/gdb/cli/cli-cmds.h | 8 +- contrib/gdb-7/gdb/cli/cli-decode.c | 227 +- contrib/gdb-7/gdb/cli/cli-decode.h | 111 +- contrib/gdb-7/gdb/cli/cli-dump.c | 29 +- contrib/gdb-7/gdb/cli/cli-dump.h | 2 +- contrib/gdb-7/gdb/cli/cli-interp.c | 3 +- contrib/gdb-7/gdb/cli/cli-logging.c | 66 +- contrib/gdb-7/gdb/cli/cli-script.c | 86 +- contrib/gdb-7/gdb/cli/cli-script.h | 13 +- contrib/gdb-7/gdb/cli/cli-setshow.c | 665 +- contrib/gdb-7/gdb/cli/cli-setshow.h | 12 +- contrib/gdb-7/gdb/cli/cli-utils.c | 61 +- contrib/gdb-7/gdb/cli/cli-utils.h | 25 +- contrib/gdb-7/gdb/coff-pe-read.c | 473 +- contrib/gdb-7/gdb/coff-pe-read.h | 7 +- contrib/gdb-7/gdb/coffread.c | 97 +- contrib/gdb-7/gdb/command.h | 79 +- contrib/gdb-7/gdb/common/agent.c | 356 + contrib/gdb-7/gdb/common/agent.h | 57 + contrib/gdb-7/gdb/common/ax.def | 4 +- contrib/gdb-7/gdb/common/btrace-common.h | 73 + contrib/gdb-7/gdb/common/buffer.c | 57 +- contrib/gdb-7/gdb/common/buffer.h | 2 +- contrib/gdb-7/gdb/common/common-utils.c | 29 +- contrib/gdb-7/gdb/common/common-utils.h | 15 +- contrib/gdb-7/gdb/common/format.c | 401 + contrib/gdb-7/gdb/common/format.h | 63 + contrib/gdb-7/gdb/common/gdb_assert.h | 4 +- contrib/gdb-7/gdb/common/gdb_dirent.h | 2 +- contrib/gdb-7/gdb/common/gdb_locale.h | 2 +- contrib/gdb-7/gdb/common/gdb_signals.h | 26 +- contrib/gdb-7/gdb/{ => common}/gdb_stat.h | 15 +- contrib/gdb-7/gdb/{ => common}/gdb_string.h | 3 +- contrib/gdb-7/gdb/common/gdb_thread_db.h | 2 +- contrib/gdb-7/gdb/common/gdb_vecs.c | 93 + .../gdb/{mi/mi-main.h => common/gdb_vecs.h} | 34 +- contrib/gdb-7/gdb/{ => common}/gdb_wait.h | 2 +- .../gdb/{gdb_select.h => common/host-defs.h} | 32 +- contrib/gdb-7/gdb/common/i386-xstate.h | 2 +- contrib/gdb-7/gdb/common/linux-btrace.c | 610 + contrib/gdb-7/gdb/common/linux-btrace.h | 77 + contrib/gdb-7/gdb/common/linux-osdata.c | 1157 +- contrib/gdb-7/gdb/common/linux-osdata.h | 2 +- contrib/gdb-7/gdb/common/linux-procfs.c | 97 +- contrib/gdb-7/gdb/common/linux-procfs.h | 18 +- contrib/gdb-7/gdb/common/linux-ptrace.c | 238 + contrib/gdb-7/gdb/common/linux-ptrace.h | 7 +- contrib/gdb-7/gdb/common/ptid.c | 2 +- contrib/gdb-7/gdb/common/ptid.h | 2 +- contrib/gdb-7/gdb/common/queue.h | 303 + contrib/gdb-7/gdb/common/signals.c | 318 +- contrib/gdb-7/gdb/{ => common}/vec.c | 7 +- contrib/gdb-7/gdb/{ => common}/vec.h | 75 +- contrib/gdb-7/gdb/common/xml-utils.c | 2 +- contrib/gdb-7/gdb/common/xml-utils.h | 2 +- contrib/gdb-7/gdb/complaints.c | 3 +- contrib/gdb-7/gdb/complaints.h | 3 +- contrib/gdb-7/gdb/completer.c | 239 +- contrib/gdb-7/gdb/completer.h | 33 +- contrib/gdb-7/gdb/config.in | 328 +- contrib/gdb-7/gdb/config/aarch64/linux.mh | 27 + contrib/gdb-7/gdb/config/i386/cygwin64.mh | 20 + contrib/gdb-7/gdb/config/tilegx/linux.mh | 12 + contrib/gdb-7/gdb/configure.ac | 335 +- contrib/gdb-7/gdb/configure.host | 8 + contrib/gdb-7/gdb/configure.tgt | 247 +- contrib/gdb-7/gdb/continuations.c | 4 +- contrib/gdb-7/gdb/continuations.h | 2 +- contrib/gdb-7/gdb/copying.c | 10 +- contrib/gdb-7/gdb/copyright.py | 844 +- contrib/gdb-7/gdb/corefile.c | 95 +- contrib/gdb-7/gdb/corelow.c | 154 +- contrib/gdb-7/gdb/cp-abi.c | 42 +- contrib/gdb-7/gdb/cp-abi.h | 8 +- contrib/gdb-7/gdb/cp-name-parser.y | 68 +- contrib/gdb-7/gdb/cp-namespace.c | 279 +- contrib/gdb-7/gdb/cp-support.c | 256 +- contrib/gdb-7/gdb/cp-support.h | 39 +- contrib/gdb-7/gdb/cp-valprint.c | 92 +- contrib/gdb-7/gdb/d-lang.c | 11 +- contrib/gdb-7/gdb/d-lang.h | 12 +- contrib/gdb-7/gdb/d-valprint.c | 33 +- contrib/gdb-7/gdb/data-directory/Makefile.in | 8 +- contrib/gdb-7/gdb/dbxread.c | 197 +- contrib/gdb-7/gdb/dcache.c | 7 +- contrib/gdb-7/gdb/dcache.h | 3 +- contrib/gdb-7/gdb/defs.h | 532 +- contrib/gdb-7/gdb/demangle.c | 3 +- contrib/gdb-7/gdb/dfp.c | 2 +- contrib/gdb-7/gdb/dfp.h | 2 +- contrib/gdb-7/gdb/dictionary.c | 29 +- contrib/gdb-7/gdb/dictionary.h | 7 +- contrib/gdb-7/gdb/disasm.c | 40 +- contrib/gdb-7/gdb/disasm.h | 4 +- contrib/gdb-7/gdb/doc/agentexpr.texi | 19 +- contrib/gdb-7/gdb/doc/all-cfg.texi | 6 +- contrib/gdb-7/gdb/doc/annotate.texinfo | 3 +- contrib/gdb-7/gdb/doc/gdb.texinfo | 4392 +++- contrib/gdb-7/gdb/doc/gdbint.texinfo | 232 +- contrib/gdb-7/gdb/doc/observer.texi | 55 +- contrib/gdb-7/gdb/doc/stabs.texinfo | 5 +- contrib/gdb-7/gdb/doublest.c | 25 +- contrib/gdb-7/gdb/doublest.h | 3 +- contrib/gdb-7/gdb/dummy-frame.c | 87 +- contrib/gdb-7/gdb/dummy-frame.h | 4 +- contrib/gdb-7/gdb/dwarf2-frame-tailcall.c | 16 +- contrib/gdb-7/gdb/dwarf2-frame-tailcall.h | 2 +- contrib/gdb-7/gdb/dwarf2-frame.c | 262 +- contrib/gdb-7/gdb/dwarf2-frame.h | 2 +- contrib/gdb-7/gdb/dwarf2expr.c | 278 +- contrib/gdb-7/gdb/dwarf2expr.h | 95 +- contrib/gdb-7/gdb/dwarf2loc.c | 673 +- contrib/gdb-7/gdb/dwarf2loc.h | 32 +- contrib/gdb-7/gdb/dwarf2read.c | 13064 +++++++----- contrib/gdb-7/gdb/elfread.c | 334 +- contrib/gdb-7/gdb/environ.c | 3 +- contrib/gdb-7/gdb/environ.h | 3 +- contrib/gdb-7/gdb/eval.c | 424 +- contrib/gdb-7/gdb/event-loop.c | 137 +- contrib/gdb-7/gdb/event-loop.h | 15 +- contrib/gdb-7/gdb/event-top.c | 64 +- contrib/gdb-7/gdb/event-top.h | 4 +- contrib/gdb-7/gdb/exceptions.c | 64 +- contrib/gdb-7/gdb/exceptions.h | 6 +- contrib/gdb-7/gdb/exec.c | 94 +- contrib/gdb-7/gdb/exec.h | 8 +- contrib/gdb-7/gdb/expprint.c | 101 +- contrib/gdb-7/gdb/expression.h | 21 +- contrib/gdb-7/gdb/f-exp.y | 31 +- contrib/gdb-7/gdb/f-lang.c | 445 +- contrib/gdb-7/gdb/f-lang.h | 68 +- contrib/gdb-7/gdb/f-typeprint.c | 7 +- contrib/gdb-7/gdb/f-valprint.c | 414 +- contrib/gdb-7/gdb/fbsd-nat.c | 17 +- contrib/gdb-7/gdb/fbsd-nat.h | 6 +- contrib/gdb-7/gdb/features/btrace.dtd | 12 + contrib/gdb-7/gdb/features/feature_to_c.sh | 2 +- contrib/gdb-7/gdb/features/gdb-target.dtd | 2 +- contrib/gdb-7/gdb/features/i386/32bit-avx.xml | 2 +- .../gdb-7/gdb/features/i386/32bit-core.xml | 2 +- .../gdb-7/gdb/features/i386/32bit-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/32bit-sse.xml | 2 +- contrib/gdb-7/gdb/features/i386/64bit-avx.xml | 2 +- .../gdb-7/gdb/features/i386/64bit-core.xml | 2 +- .../gdb-7/gdb/features/i386/64bit-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/64bit-sse.xml | 2 +- .../gdb-7/gdb/features/i386/amd64-avx-linux.c | 6 +- .../gdb/features/i386/amd64-avx-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/amd64-avx.c | 6 +- contrib/gdb-7/gdb/features/i386/amd64-avx.xml | 2 +- contrib/gdb-7/gdb/features/i386/amd64-linux.c | 6 +- .../gdb-7/gdb/features/i386/amd64-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/amd64.c | 6 +- contrib/gdb-7/gdb/features/i386/amd64.xml | 2 +- .../gdb-7/gdb/features/i386/i386-avx-linux.c | 6 +- .../gdb/features/i386/i386-avx-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/i386-avx.c | 6 +- contrib/gdb-7/gdb/features/i386/i386-avx.xml | 2 +- contrib/gdb-7/gdb/features/i386/i386-linux.c | 6 +- .../gdb-7/gdb/features/i386/i386-linux.xml | 2 +- .../gdb-7/gdb/features/i386/i386-mmx-linux.c | 5 +- .../gdb/features/i386/i386-mmx-linux.xml | 2 +- contrib/gdb-7/gdb/features/i386/i386-mmx.c | 3 +- contrib/gdb-7/gdb/features/i386/i386-mmx.xml | 2 +- contrib/gdb-7/gdb/features/i386/i386.c | 6 +- contrib/gdb-7/gdb/features/i386/i386.xml | 2 +- .../{amd64-avx-linux.c => x32-avx-linux.c} | 20 +- ...{amd64-avx-linux.xml => x32-avx-linux.xml} | 8 +- .../features/i386/{amd64-avx.c => x32-avx.c} | 20 +- .../i386/{amd64-avx.xml => x32-avx.xml} | 8 +- .../i386/{64bit-core.xml => x32-core.xml} | 8 +- .../i386/{amd64-linux.c => x32-linux.c} | 20 +- .../i386/{amd64-linux.xml => x32-linux.xml} | 8 +- .../gdb/features/i386/{amd64.c => x32.c} | 20 +- .../gdb/features/i386/{amd64.xml => x32.xml} | 8 +- .../gdb-7/gdb/features/library-list-svr4.dtd | 2 +- contrib/gdb-7/gdb/features/library-list.dtd | 2 +- contrib/gdb-7/gdb/features/osdata.dtd | 2 +- contrib/gdb-7/gdb/features/threads.dtd | 2 +- .../gdb-7/gdb/features/traceframe-info.dtd | 2 +- contrib/gdb-7/gdb/features/xinclude.dtd | 2 +- contrib/gdb-7/gdb/filesystem.c | 6 +- contrib/gdb-7/gdb/filesystem.h | 2 +- contrib/gdb-7/gdb/findcmd.c | 43 +- contrib/gdb-7/gdb/findvar.c | 86 +- contrib/gdb-7/gdb/fork-child.c | 18 +- contrib/gdb-7/gdb/frame-base.c | 2 +- contrib/gdb-7/gdb/frame-base.h | 2 +- contrib/gdb-7/gdb/frame-unwind.c | 2 +- contrib/gdb-7/gdb/frame-unwind.h | 6 +- contrib/gdb-7/gdb/frame.c | 108 +- contrib/gdb-7/gdb/frame.h | 45 +- contrib/gdb-7/gdb/gcore.c | 104 +- contrib/gdb-7/gdb/gcore.h | 2 +- contrib/gdb-7/gdb/gdb-code-style.el | 77 + contrib/gdb-7/gdb/gdb-demangle.h | 2 +- contrib/gdb-7/gdb/gdb-dlfcn.c | 2 +- contrib/gdb-7/gdb/gdb-dlfcn.h | 2 +- .../gdb-7/gdb/{gdbinit.in => gdb-gdb.gdb.in} | 27 +- contrib/gdb-7/gdb/gdb-gdb.py | 12 +- contrib/gdb-7/gdb/gdb-stabs.h | 14 +- contrib/gdb-7/gdb/gdb.1 | 38 +- contrib/gdb-7/gdb/gdb.c | 2 +- contrib/gdb-7/gdb/gdb.h | 2 +- contrib/gdb-7/gdb/gdb_bfd.c | 601 + contrib/gdb-7/gdb/gdb_bfd.h | 118 + contrib/gdb-7/gdb/gdb_curses.h | 20 +- .../gdb/{tui/tui-main.c => gdb_obstack.c} | 46 +- contrib/gdb-7/gdb/gdb_obstack.h | 9 +- contrib/gdb-7/gdb/gdb_ptrace.h | 2 +- contrib/gdb-7/gdb/gdb_regex.h | 3 +- contrib/gdb-7/gdb/gdb_select.h | 2 +- contrib/gdb-7/gdb/gdb_usleep.c | 2 +- contrib/gdb-7/gdb/gdb_usleep.h | 2 +- contrib/gdb-7/gdb/gdb_vfork.h | 2 +- contrib/gdb-7/gdb/gdb_wchar.h | 2 +- contrib/gdb-7/gdb/gdbarch.c | 609 +- contrib/gdb-7/gdb/gdbarch.h | 304 +- contrib/gdb-7/gdb/gdbcmd.h | 13 +- contrib/gdb-7/gdb/gdbcore.h | 16 +- contrib/gdb-7/gdb/gdbthread.h | 20 +- contrib/gdb-7/gdb/gdbtypes.c | 324 +- contrib/gdb-7/gdb/gdbtypes.h | 207 +- contrib/gdb-7/gdb/gnu-v2-abi.c | 15 +- contrib/gdb-7/gdb/gnu-v3-abi.c | 273 +- contrib/gdb-7/gdb/gnulib/import/fnmatch.c | 350 + .../gdb-7/gdb/gnulib/import/fnmatch_loop.c | 1219 ++ .../gdb-7/gdb/gnulib/import/localcharset.c | 553 + .../gdb-7/gdb/gnulib/import/localcharset.h | 40 + contrib/gdb-7/gdb/gnulib/import/memmem.c | 75 + contrib/gdb-7/gdb/gnulib/import/str-two-way.h | 452 + contrib/gdb-7/gdb/gnulib/import/strnlen1.c | 35 + contrib/gdb-7/gdb/gnulib/import/strnlen1.h | 40 + contrib/gdb-7/gdb/gnulib/import/wctype-h.c | 4 + contrib/gdb-7/gdb/go-exp.c | 3432 ++++ contrib/gdb-7/gdb/go-exp.y | 1623 ++ contrib/gdb-7/gdb/go-lang.c | 666 + contrib/gdb-7/gdb/go-lang.h | 91 + contrib/gdb-7/gdb/go-typeprint.c | 63 + contrib/gdb-7/gdb/go-valprint.c | 123 + contrib/gdb-7/gdb/gregset.h | 63 + contrib/gdb-7/gdb/i386-nat.c | 256 +- contrib/gdb-7/gdb/i386-nat.h | 51 +- contrib/gdb-7/gdb/i386-tdep.c | 1155 +- contrib/gdb-7/gdb/i386-tdep.h | 13 +- contrib/gdb-7/gdb/i386bsd-nat.c | 37 +- contrib/gdb-7/gdb/i386bsd-nat.h | 6 +- contrib/gdb-7/gdb/i386bsd-tdep.c | 2 +- contrib/gdb-7/gdb/i386fbsd-tdep.c | 6 +- contrib/gdb-7/gdb/i387-tdep.c | 201 +- contrib/gdb-7/gdb/i387-tdep.h | 2 +- contrib/gdb-7/gdb/inf-child.c | 288 +- contrib/gdb-7/gdb/inf-child.h | 7 +- contrib/gdb-7/gdb/inf-loop.c | 8 +- contrib/gdb-7/gdb/inf-loop.h | 2 +- contrib/gdb-7/gdb/inf-ptrace.c | 69 +- contrib/gdb-7/gdb/inf-ptrace.h | 2 +- contrib/gdb-7/gdb/infcall.c | 119 +- contrib/gdb-7/gdb/infcall.h | 2 +- contrib/gdb-7/gdb/infcmd.c | 531 +- contrib/gdb-7/gdb/inferior.c | 195 +- contrib/gdb-7/gdb/inferior.h | 92 +- contrib/gdb-7/gdb/inflow.c | 4 +- contrib/gdb-7/gdb/inflow.h | 2 +- contrib/gdb-7/gdb/infrun.c | 1598 +- contrib/gdb-7/gdb/inline-frame.c | 5 +- contrib/gdb-7/gdb/inline-frame.h | 2 +- contrib/gdb-7/gdb/interps.c | 71 +- contrib/gdb-7/gdb/interps.h | 24 +- contrib/gdb-7/gdb/jit-reader.in | 6 +- contrib/gdb-7/gdb/jit.c | 446 +- contrib/gdb-7/gdb/jit.h | 2 +- contrib/gdb-7/gdb/jv-exp.y | 14 +- contrib/gdb-7/gdb/jv-lang.c | 37 +- contrib/gdb-7/gdb/jv-lang.h | 23 +- contrib/gdb-7/gdb/jv-typeprint.c | 33 +- contrib/gdb-7/gdb/jv-valprint.c | 101 +- contrib/gdb-7/gdb/language.c | 433 +- contrib/gdb-7/gdb/language.h | 136 +- contrib/gdb-7/gdb/linespec.c | 4147 ++-- contrib/gdb-7/gdb/linespec.h | 15 +- contrib/gdb-7/gdb/m2-exp.y | 48 +- contrib/gdb-7/gdb/m2-lang.c | 24 +- contrib/gdb-7/gdb/m2-lang.h | 15 +- contrib/gdb-7/gdb/m2-typeprint.c | 102 +- contrib/gdb-7/gdb/m2-valprint.c | 284 +- contrib/gdb-7/gdb/machoread.c | 1054 + contrib/gdb-7/gdb/macrocmd.c | 21 +- contrib/gdb-7/gdb/macroexp.c | 32 +- contrib/gdb-7/gdb/macroexp.h | 7 +- contrib/gdb-7/gdb/macroscope.c | 6 +- contrib/gdb-7/gdb/macroscope.h | 2 +- contrib/gdb-7/gdb/macrotab.c | 158 +- contrib/gdb-7/gdb/macrotab.h | 49 +- contrib/gdb-7/gdb/main.c | 233 +- contrib/gdb-7/gdb/main.h | 8 +- contrib/gdb-7/gdb/maint.c | 48 +- contrib/gdb-7/gdb/mdebugread.c | 124 +- contrib/gdb-7/gdb/mdebugread.h | 2 +- contrib/gdb-7/gdb/mem-break.c | 24 +- contrib/gdb-7/gdb/memattr.c | 12 +- contrib/gdb-7/gdb/memattr.h | 2 +- contrib/gdb-7/gdb/memory-map.c | 2 +- contrib/gdb-7/gdb/memory-map.h | 2 +- contrib/gdb-7/gdb/memrange.c | 2 +- contrib/gdb-7/gdb/memrange.h | 2 +- contrib/gdb-7/gdb/mi/mi-cmd-break.c | 81 +- .../{tui/tui-command.h => mi/mi-cmd-break.h} | 18 +- contrib/gdb-7/gdb/mi/mi-cmd-catch.c | 101 + contrib/gdb-7/gdb/mi/mi-cmd-disas.c | 53 +- contrib/gdb-7/gdb/mi/mi-cmd-env.c | 38 +- contrib/gdb-7/gdb/mi/mi-cmd-file.c | 40 +- contrib/gdb-7/gdb/{gdb.c => mi/mi-cmd-info.c} | 33 +- contrib/gdb-7/gdb/mi/mi-cmd-stack.c | 83 +- contrib/gdb-7/gdb/mi/mi-cmd-target.c | 54 +- contrib/gdb-7/gdb/mi/mi-cmd-var.c | 133 +- contrib/gdb-7/gdb/mi/mi-cmds.c | 265 +- contrib/gdb-7/gdb/mi/mi-cmds.h | 23 +- contrib/gdb-7/gdb/mi/mi-common.c | 5 +- contrib/gdb-7/gdb/mi/mi-common.h | 2 +- contrib/gdb-7/gdb/mi/mi-console.c | 56 +- contrib/gdb-7/gdb/mi/mi-console.h | 5 +- contrib/gdb-7/gdb/mi/mi-getopt.c | 48 +- contrib/gdb-7/gdb/mi/mi-getopt.h | 36 +- contrib/gdb-7/gdb/mi/mi-interp.c | 409 +- contrib/gdb-7/gdb/mi/mi-main.c | 515 +- contrib/gdb-7/gdb/mi/mi-main.h | 16 +- contrib/gdb-7/gdb/mi/mi-out.c | 98 +- contrib/gdb-7/gdb/mi/mi-out.h | 2 +- contrib/gdb-7/gdb/mi/mi-parse.c | 97 +- contrib/gdb-7/gdb/mi/mi-parse.h | 6 +- contrib/gdb-7/gdb/mi/mi-symbol-cmds.c | 16 +- contrib/gdb-7/gdb/minidebug.c | 290 + contrib/gdb-7/gdb/minsyms.c | 136 +- contrib/gdb-7/gdb/minsyms.h | 245 + contrib/gdb-7/gdb/mipsread.c | 4 +- contrib/gdb-7/gdb/objc-exp.y | 1787 -- contrib/gdb-7/gdb/objc-lang.c | 233 +- contrib/gdb-7/gdb/objc-lang.h | 8 +- contrib/gdb-7/gdb/objfiles.c | 450 +- contrib/gdb-7/gdb/objfiles.h | 128 +- contrib/gdb-7/gdb/observer.c | 19 +- contrib/gdb-7/gdb/observer.sh | 14 +- contrib/gdb-7/gdb/opencl-lang.c | 134 +- contrib/gdb-7/gdb/osabi.c | 38 +- contrib/gdb-7/gdb/osabi.h | 2 +- contrib/gdb-7/gdb/osdata.c | 42 +- contrib/gdb-7/gdb/osdata.h | 3 +- contrib/gdb-7/gdb/p-exp.y | 52 +- contrib/gdb-7/gdb/p-lang.c | 26 +- contrib/gdb-7/gdb/p-lang.h | 24 +- contrib/gdb-7/gdb/p-typeprint.c | 86 +- contrib/gdb-7/gdb/p-valprint.c | 332 +- contrib/gdb-7/gdb/parse.c | 465 +- contrib/gdb-7/gdb/parser-defs.h | 95 +- contrib/gdb-7/gdb/posix-hdep.c | 2 +- contrib/gdb-7/gdb/ppc-ravenscar-thread.c | 291 + .../xml-utils.h => ppc-ravenscar-thread.h} | 15 +- contrib/gdb-7/gdb/printcmd.c | 933 +- contrib/gdb-7/gdb/probe.c | 760 + contrib/gdb-7/gdb/probe.h | 225 + contrib/gdb-7/gdb/proc-service.list | 2 +- contrib/gdb-7/gdb/progspace.c | 128 +- contrib/gdb-7/gdb/progspace.h | 37 +- contrib/gdb-7/gdb/prologue-value.c | 2 +- contrib/gdb-7/gdb/prologue-value.h | 2 +- contrib/gdb-7/gdb/psympriv.h | 82 +- contrib/gdb-7/gdb/psymtab.c | 605 +- contrib/gdb-7/gdb/psymtab.h | 5 +- contrib/gdb-7/gdb/python/lib/gdb/__init__.py | 121 +- .../gdb/python/lib/gdb/command/__init__.py | 2 +- .../gdb/python/lib/gdb/command/explore.py | 760 + .../python/lib/gdb/command/pretty_printers.py | 22 +- .../gdb/python/lib/gdb/command/prompt.py | 2 +- .../python/lib/gdb/command/type_printers.py | 125 + .../lib/gdb/{command => function}/__init__.py | 4 +- .../gdb/python/lib/gdb/function/strfns.py | 108 + contrib/gdb-7/gdb/python/lib/gdb/printing.py | 57 +- contrib/gdb-7/gdb/python/lib/gdb/prompt.py | 5 +- contrib/gdb-7/gdb/python/lib/gdb/types.py | 71 +- contrib/gdb-7/gdb/python/py-arch.c | 294 + contrib/gdb-7/gdb/python/py-auto-load.c | 590 +- contrib/gdb-7/gdb/python/py-block.c | 28 +- contrib/gdb-7/gdb/python/py-bpevent.c | 6 +- contrib/gdb-7/gdb/python/py-breakpoint.c | 10 +- contrib/gdb-7/gdb/python/py-cmd.c | 25 +- contrib/gdb-7/gdb/python/py-continueevent.c | 5 +- contrib/gdb-7/gdb/python/py-event.c | 20 +- contrib/gdb-7/gdb/python/py-event.h | 6 +- contrib/gdb-7/gdb/python/py-events.h | 3 +- contrib/gdb-7/gdb/python/py-evtregistry.c | 7 +- contrib/gdb-7/gdb/python/py-evts.c | 24 +- contrib/gdb-7/gdb/python/py-exitedevent.c | 32 +- .../gdb-7/gdb/python/py-finishbreakpoint.c | 114 +- contrib/gdb-7/gdb/python/py-frame.c | 33 +- contrib/gdb-7/gdb/python/py-function.c | 5 +- contrib/gdb-7/gdb/python/py-gdb-readline.c | 113 + contrib/gdb-7/gdb/python/py-inferior.c | 150 +- contrib/gdb-7/gdb/python/py-infthread.c | 8 +- contrib/gdb-7/gdb/python/py-lazy-string.c | 7 +- contrib/gdb-7/gdb/python/py-newobjfileevent.c | 7 +- contrib/gdb-7/gdb/python/py-objfile.c | 69 +- contrib/gdb-7/gdb/python/py-param.c | 13 +- contrib/gdb-7/gdb/python/py-prettyprint.c | 21 +- contrib/gdb-7/gdb/python/py-progspace.c | 71 +- contrib/gdb-7/gdb/python/py-signalevent.c | 21 +- contrib/gdb-7/gdb/python/py-stopevent.c | 10 +- contrib/gdb-7/gdb/python/py-stopevent.h | 6 +- contrib/gdb-7/gdb/python/py-symbol.c | 102 +- contrib/gdb-7/gdb/python/py-symtab.c | 91 +- contrib/gdb-7/gdb/python/py-threadevent.c | 7 +- contrib/gdb-7/gdb/python/py-type.c | 108 +- contrib/gdb-7/gdb/python/py-utils.c | 79 +- contrib/gdb-7/gdb/python/py-value.c | 188 +- contrib/gdb-7/gdb/python/python-config.py | 15 +- contrib/gdb-7/gdb/python/python-internal.h | 52 +- contrib/gdb-7/gdb/python/python.c | 793 +- contrib/gdb-7/gdb/python/python.h | 16 +- contrib/gdb-7/gdb/ravenscar-thread.c | 91 +- contrib/gdb-7/gdb/ravenscar-thread.h | 11 +- contrib/gdb-7/gdb/record-btrace.c | 696 + contrib/gdb-7/gdb/{record.c => record-full.c} | 2121 +- contrib/gdb-7/gdb/{record.h => record-full.h} | 21 +- contrib/gdb-7/gdb/record.c | 3153 +-- contrib/gdb-7/gdb/record.h | 47 +- contrib/gdb-7/gdb/regcache.c | 15 +- contrib/gdb-7/gdb/regcache.h | 3 +- .../gdb/regformats/i386/x32-avx-linux.dat | 78 + contrib/gdb-7/gdb/regformats/i386/x32-avx.dat | 77 + .../gdb-7/gdb/regformats/i386/x32-linux.dat | 62 + contrib/gdb-7/gdb/regformats/i386/x32.dat | 61 + contrib/gdb-7/gdb/regformats/regdat.sh | 4 +- contrib/gdb-7/gdb/regformats/regdef.h | 2 +- contrib/gdb-7/gdb/reggroups.c | 2 +- contrib/gdb-7/gdb/reggroups.h | 2 +- contrib/gdb-7/gdb/registry.c | 115 + contrib/gdb-7/gdb/registry.h | 256 + contrib/gdb-7/gdb/regset.c | 2 +- contrib/gdb-7/gdb/regset.h | 2 +- contrib/gdb-7/gdb/remote-fileio.c | 10 +- contrib/gdb-7/gdb/remote-fileio.h | 2 +- contrib/gdb-7/gdb/remote-notif.c | 281 + contrib/gdb-7/gdb/remote-notif.h | 85 + contrib/gdb-7/gdb/remote.c | 1792 +- contrib/gdb-7/gdb/remote.h | 9 +- contrib/gdb-7/gdb/reverse.c | 3 +- contrib/gdb-7/gdb/sentinel-frame.c | 2 +- contrib/gdb-7/gdb/sentinel-frame.h | 2 +- contrib/gdb-7/gdb/ser-base.c | 146 +- contrib/gdb-7/gdb/ser-base.h | 2 +- contrib/gdb-7/gdb/ser-pipe.c | 27 +- contrib/gdb-7/gdb/ser-tcp.c | 5 +- contrib/gdb-7/gdb/ser-tcp.h | 2 +- contrib/gdb-7/gdb/ser-unix.c | 3 +- contrib/gdb-7/gdb/ser-unix.h | 3 +- contrib/gdb-7/gdb/serial.c | 249 +- contrib/gdb-7/gdb/serial.h | 38 +- contrib/gdb-7/gdb/sim-regno.h | 2 +- contrib/gdb-7/gdb/skip.c | 328 +- contrib/gdb-7/gdb/skip.h | 12 +- contrib/gdb-7/gdb/solib-svr4.c | 140 +- contrib/gdb-7/gdb/solib-svr4.h | 2 +- contrib/gdb-7/gdb/solib-target.c | 13 +- contrib/gdb-7/gdb/solib-target.h | 2 +- contrib/gdb-7/gdb/solib.c | 73 +- contrib/gdb-7/gdb/solib.h | 11 +- contrib/gdb-7/gdb/solist.h | 3 +- contrib/gdb-7/gdb/somread.c | 433 + contrib/gdb-7/gdb/source.c | 458 +- contrib/gdb-7/gdb/source.h | 33 +- ...parc-thread.c => sparc-ravenscar-thread.c} | 37 +- .../{gdb_vfork.h => sparc-ravenscar-thread.h} | 16 +- contrib/gdb-7/gdb/stabsread.c | 98 +- contrib/gdb-7/gdb/stabsread.h | 10 +- contrib/gdb-7/gdb/stack.c | 295 +- contrib/gdb-7/gdb/stack.h | 4 +- contrib/gdb-7/gdb/stap-probe.c | 1583 ++ contrib/gdb-7/gdb/stap-probe.h | 50 + contrib/gdb-7/gdb/std-operator.def | 42 +- contrib/gdb-7/gdb/std-regs.c | 2 +- contrib/gdb-7/gdb/stubs/ChangeLog | 21 + contrib/gdb-7/gdb/stubs/buildvms.com | 29 + contrib/gdb-7/gdb/stubs/i386-stub.c | 952 + contrib/gdb-7/gdb/stubs/ia64vms-stub.c | 2602 +++ contrib/gdb-7/gdb/stubs/m32r-stub.c | 1779 ++ contrib/gdb-7/gdb/stubs/m68k-stub.c | 1098 + contrib/gdb-7/gdb/stubs/sh-stub.c | 1583 ++ contrib/gdb-7/gdb/stubs/sparc-stub.c | 778 + contrib/gdb-7/gdb/symfile.c | 640 +- contrib/gdb-7/gdb/symfile.h | 133 +- contrib/gdb-7/gdb/symmisc.c | 140 +- contrib/gdb-7/gdb/symtab.c | 1289 +- contrib/gdb-7/gdb/symtab.h | 320 +- contrib/gdb-7/gdb/syscalls/gdb-syscalls.dtd | 2 +- contrib/gdb-7/gdb/target-descriptions.c | 147 +- contrib/gdb-7/gdb/target-descriptions.h | 36 +- contrib/gdb-7/gdb/target-memory.c | 2 +- contrib/gdb-7/gdb/target.c | 930 +- contrib/gdb-7/gdb/target.h | 384 +- contrib/gdb-7/gdb/terminal.h | 3 +- contrib/gdb-7/gdb/thread.c | 39 +- contrib/gdb-7/gdb/top.c | 227 +- contrib/gdb-7/gdb/top.h | 8 +- contrib/gdb-7/gdb/tracepoint.c | 571 +- contrib/gdb-7/gdb/tracepoint.h | 19 +- contrib/gdb-7/gdb/trad-frame.c | 2 +- contrib/gdb-7/gdb/trad-frame.h | 2 +- contrib/gdb-7/gdb/tramp-frame.c | 2 +- contrib/gdb-7/gdb/tramp-frame.h | 2 +- contrib/gdb-7/gdb/tui/tui-command.c | 2 +- contrib/gdb-7/gdb/tui/tui-command.h | 3 +- contrib/gdb-7/gdb/tui/tui-data.c | 28 +- contrib/gdb-7/gdb/tui/tui-data.h | 13 +- contrib/gdb-7/gdb/tui/tui-disasm.c | 10 +- contrib/gdb-7/gdb/tui/tui-disasm.h | 3 +- contrib/gdb-7/gdb/tui/tui-file.c | 2 +- contrib/gdb-7/gdb/tui/tui-file.h | 2 +- contrib/gdb-7/gdb/tui/tui-hooks.c | 54 +- contrib/gdb-7/gdb/tui/tui-hooks.h | 2 +- contrib/gdb-7/gdb/tui/tui-interp.c | 2 +- contrib/gdb-7/gdb/tui/tui-io.c | 12 +- contrib/gdb-7/gdb/tui/tui-io.h | 3 +- contrib/gdb-7/gdb/tui/tui-layout.c | 2 +- contrib/gdb-7/gdb/tui/tui-layout.h | 3 +- contrib/gdb-7/gdb/tui/tui-out.c | 5 +- contrib/gdb-7/gdb/tui/tui-regs.c | 22 +- contrib/gdb-7/gdb/tui/tui-regs.h | 3 +- contrib/gdb-7/gdb/tui/tui-source.c | 40 +- contrib/gdb-7/gdb/tui/tui-source.h | 5 +- contrib/gdb-7/gdb/tui/tui-stack.c | 38 +- contrib/gdb-7/gdb/tui/tui-stack.h | 5 +- contrib/gdb-7/gdb/tui/tui-win.c | 32 +- contrib/gdb-7/gdb/tui/tui-win.h | 3 +- contrib/gdb-7/gdb/tui/tui-windata.c | 2 +- contrib/gdb-7/gdb/tui/tui-windata.h | 3 +- contrib/gdb-7/gdb/tui/tui-wingeneral.c | 2 +- contrib/gdb-7/gdb/tui/tui-wingeneral.h | 3 +- contrib/gdb-7/gdb/tui/tui-winsource.c | 11 +- contrib/gdb-7/gdb/tui/tui-winsource.h | 3 +- contrib/gdb-7/gdb/tui/tui.c | 25 +- contrib/gdb-7/gdb/tui/tui.h | 5 +- contrib/gdb-7/gdb/typeprint.c | 453 +- contrib/gdb-7/gdb/typeprint.h | 52 +- contrib/gdb-7/gdb/ui-file.c | 87 +- contrib/gdb-7/gdb/ui-file.h | 17 +- contrib/gdb-7/gdb/ui-out.c | 142 +- contrib/gdb-7/gdb/ui-out.h | 52 +- contrib/gdb-7/gdb/unwind_stop_reasons.def | 2 +- contrib/gdb-7/gdb/user-regs.c | 2 +- contrib/gdb-7/gdb/user-regs.h | 2 +- contrib/gdb-7/gdb/utils.c | 671 +- contrib/gdb-7/gdb/utils.h | 381 + contrib/gdb-7/gdb/valarith.c | 129 +- contrib/gdb-7/gdb/valops.c | 396 +- contrib/gdb-7/gdb/valprint.c | 951 +- contrib/gdb-7/gdb/valprint.h | 54 +- contrib/gdb-7/gdb/value.c | 361 +- contrib/gdb-7/gdb/value.h | 183 +- contrib/gdb-7/gdb/varobj.c | 793 +- contrib/gdb-7/gdb/varobj.h | 3 +- contrib/gdb-7/gdb/version.h | 2 +- contrib/gdb-7/gdb/version.in | 2 +- contrib/gdb-7/gdb/wrapper.c | 185 - contrib/gdb-7/gdb/wrapper.h | 53 - contrib/gdb-7/gdb/xcoffsolib.h | 3 +- contrib/gdb-7/gdb/xml-support.c | 2 +- contrib/gdb-7/gdb/xml-support.h | 2 +- contrib/gdb-7/gdb/xml-syscall.c | 4 +- contrib/gdb-7/gdb/xml-syscall.h | 2 +- contrib/gdb-7/gdb/xml-tdesc.c | 2 +- contrib/gdb-7/gdb/xml-tdesc.h | 2 +- contrib/gdb-7/include/ansidecl.h | 9 +- contrib/gdb-7/include/bfdlink.h | 38 +- contrib/gdb-7/include/demangle.h | 10 + contrib/gdb-7/include/dis-asm.h | 14 +- contrib/gdb-7/include/dwarf2.def | 685 + contrib/gdb-7/include/dwarf2.h | 728 +- contrib/gdb-7/include/elf/common.h | 51 +- contrib/gdb-7/include/elf/i386.h | 2 +- contrib/gdb-7/include/elf/mips.h | 20 +- contrib/gdb-7/include/elf/x86-64.h | 3 +- contrib/gdb-7/include/filenames.h | 6 + contrib/gdb-7/include/fopen-bin.h | 19 +- contrib/gdb-7/include/fopen-same.h | 19 +- contrib/gdb-7/include/gdb/fileio.h | 2 +- contrib/gdb-7/include/gdb/gdb-index.h | 99 + contrib/gdb-7/include/gdb/signals.def | 302 +- contrib/gdb-7/include/gdb/signals.h | 6 +- contrib/gdb-7/include/gdb/sim-bfin.h | 2 +- contrib/gdb-7/include/leb128.h | 136 + contrib/gdb-7/include/mach-o/ChangeLog | 62 + contrib/gdb-7/include/mach-o/external.h | 85 +- contrib/gdb-7/include/mach-o/loader.h | 51 +- contrib/gdb-7/include/mach-o/reloc.h | 22 +- contrib/gdb-7/include/objalloc.h | 4 +- contrib/gdb-7/include/opcode/i386.h | 2 + contrib/gdb-7/include/splay-tree.h | 19 +- contrib/gdb-7/libdecnumber/dconfig.h | 2 +- contrib/gdb-7/libdecnumber/decContext.c | 2 +- contrib/gdb-7/libdecnumber/decContext.h | 2 +- contrib/gdb-7/libdecnumber/decDPD.h | 2 +- contrib/gdb-7/libdecnumber/decNumber.c | 2 +- contrib/gdb-7/libdecnumber/decNumber.h | 2 +- contrib/gdb-7/libdecnumber/decNumberLocal.h | 2 +- contrib/gdb-7/libdecnumber/dpd/decimal128.c | 2 +- contrib/gdb-7/libdecnumber/dpd/decimal128.h | 2 +- .../gdb-7/libdecnumber/dpd/decimal128Local.h | 2 +- contrib/gdb-7/libdecnumber/dpd/decimal32.c | 2 +- contrib/gdb-7/libdecnumber/dpd/decimal32.h | 2 +- contrib/gdb-7/libdecnumber/dpd/decimal64.c | 2 +- contrib/gdb-7/libdecnumber/dpd/decimal64.h | 2 +- contrib/gdb-7/libiberty/argv.c | 51 +- contrib/gdb-7/libiberty/cp-demangle.c | 440 +- contrib/gdb-7/libiberty/dwarfnames.c | 98 + contrib/gdb-7/libiberty/filename_cmp.c | 49 + contrib/gdb-7/libiberty/floatformat.c | 38 +- .../gdb-7/libiberty/make-relative-prefix.c | 24 +- contrib/gdb-7/libiberty/objalloc.c | 11 +- contrib/gdb-7/libiberty/pex-unix.c | 6 +- contrib/gdb-7/libiberty/regex.c | 10 +- .../gdb-7/libiberty/simple-object-common.h | 1 + .../gdb-7/libiberty/simple-object-mach-o.c | 5 +- contrib/gdb-7/libiberty/simple-object-xcoff.c | 898 + contrib/gdb-7/libiberty/simple-object.c | 3 +- contrib/gdb-7/libiberty/stack-limit.c | 3 +- contrib/gdb-7/libiberty/strnlen.c | 30 + contrib/gdb-7/opcodes/disassemble.c | 64 +- contrib/gdb-7/opcodes/i386-dis.c | 535 +- contrib/gdb-7/opcodes/i386-opc.h | 44 +- contrib/gdb-7/opcodes/i386-tbl.h | 17056 +++++++++------- contrib/gdb-7/opcodes/sysdep.h | 11 +- contrib/gdb-7/readline/signals.c | 2 + contrib/gdb-7/readline/terminal.c | 19 - 747 files changed, 108955 insertions(+), 46268 deletions(-) create mode 100644 contrib/gdb-7/bfd/elf-linux-psinfo.h create mode 100644 contrib/gdb-7/bfd/elf-nacl.c copy contrib/gdb-7/{gdb/gdb_vfork.h => bfd/elf-nacl.h} (55%) create mode 100644 contrib/gdb-7/gdb/ada-exp.c create mode 100644 contrib/gdb-7/gdb/ada-varobj.c create mode 100644 contrib/gdb-7/gdb/ada-varobj.h create mode 100644 contrib/gdb-7/gdb/agent.c copy contrib/gdb-7/gdb/{gdb_select.h => amd64bsd-nat.h} (57%) create mode 100644 contrib/gdb-7/gdb/auto-load.c create mode 100644 contrib/gdb-7/gdb/auto-load.h create mode 100644 contrib/gdb-7/gdb/break-catch-sig.c create mode 100644 contrib/gdb-7/gdb/btrace.c create mode 100644 contrib/gdb-7/gdb/btrace.h delete mode 100644 contrib/gdb-7/gdb/call-cmds.h delete mode 100644 contrib/gdb-7/gdb/cc-with-index.sh create mode 100644 contrib/gdb-7/gdb/cleanups.c create mode 100644 contrib/gdb-7/gdb/cleanups.h create mode 100644 contrib/gdb-7/gdb/common/agent.c create mode 100644 contrib/gdb-7/gdb/common/agent.h create mode 100644 contrib/gdb-7/gdb/common/btrace-common.h create mode 100644 contrib/gdb-7/gdb/common/format.c create mode 100644 contrib/gdb-7/gdb/common/format.h rename contrib/gdb-7/gdb/{ => common}/gdb_stat.h (88%) rename contrib/gdb-7/gdb/{ => common}/gdb_string.h (95%) create mode 100644 contrib/gdb-7/gdb/common/gdb_vecs.c copy contrib/gdb-7/gdb/{mi/mi-main.h => common/gdb_vecs.h} (53%) rename contrib/gdb-7/gdb/{ => common}/gdb_wait.h (98%) copy contrib/gdb-7/gdb/{gdb_select.h => common/host-defs.h} (60%) create mode 100644 contrib/gdb-7/gdb/common/linux-btrace.c create mode 100644 contrib/gdb-7/gdb/common/linux-btrace.h create mode 100644 contrib/gdb-7/gdb/common/linux-ptrace.c create mode 100644 contrib/gdb-7/gdb/common/queue.h rename contrib/gdb-7/gdb/{ => common}/vec.c (96%) rename contrib/gdb-7/gdb/{ => common}/vec.h (92%) create mode 100644 contrib/gdb-7/gdb/config/aarch64/linux.mh create mode 100644 contrib/gdb-7/gdb/config/i386/cygwin64.mh create mode 100644 contrib/gdb-7/gdb/config/tilegx/linux.mh create mode 100644 contrib/gdb-7/gdb/features/btrace.dtd copy contrib/gdb-7/gdb/features/i386/{amd64-avx-linux.c => x32-avx-linux.c} (93%) copy contrib/gdb-7/gdb/features/i386/{amd64-avx-linux.xml => x32-avx-linux.xml} (66%) copy contrib/gdb-7/gdb/features/i386/{amd64-avx.c => x32-avx.c} (93%) copy contrib/gdb-7/gdb/features/i386/{amd64-avx.xml => x32-avx.xml} (68%) copy contrib/gdb-7/gdb/features/i386/{64bit-core.xml => x32-core.xml} (93%) copy contrib/gdb-7/gdb/features/i386/{amd64-linux.c => x32-linux.c} (93%) copy contrib/gdb-7/gdb/features/i386/{amd64-linux.xml => x32-linux.xml} (65%) copy contrib/gdb-7/gdb/features/i386/{amd64.c => x32.c} (93%) copy contrib/gdb-7/gdb/features/i386/{amd64.xml => x32.xml} (67%) create mode 100644 contrib/gdb-7/gdb/gdb-code-style.el rename contrib/gdb-7/gdb/{gdbinit.in => gdb-gdb.gdb.in} (53%) create mode 100644 contrib/gdb-7/gdb/gdb_bfd.c create mode 100644 contrib/gdb-7/gdb/gdb_bfd.h rename contrib/gdb-7/gdb/{tui/tui-main.c => gdb_obstack.c} (52%) create mode 100644 contrib/gdb-7/gdb/gnulib/import/fnmatch.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/fnmatch_loop.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/localcharset.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/localcharset.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/memmem.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/str-two-way.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/strnlen1.c create mode 100644 contrib/gdb-7/gdb/gnulib/import/strnlen1.h create mode 100644 contrib/gdb-7/gdb/gnulib/import/wctype-h.c create mode 100644 contrib/gdb-7/gdb/go-exp.c create mode 100644 contrib/gdb-7/gdb/go-exp.y create mode 100644 contrib/gdb-7/gdb/go-lang.c create mode 100644 contrib/gdb-7/gdb/go-lang.h create mode 100644 contrib/gdb-7/gdb/go-typeprint.c create mode 100644 contrib/gdb-7/gdb/go-valprint.c create mode 100644 contrib/gdb-7/gdb/gregset.h create mode 100644 contrib/gdb-7/gdb/machoread.c copy contrib/gdb-7/gdb/{tui/tui-command.h => mi/mi-cmd-break.h} (67%) create mode 100644 contrib/gdb-7/gdb/mi/mi-cmd-catch.c copy contrib/gdb-7/gdb/{gdb.c => mi/mi-cmd-info.c} (62%) create mode 100644 contrib/gdb-7/gdb/minidebug.c create mode 100644 contrib/gdb-7/gdb/minsyms.h delete mode 100644 contrib/gdb-7/gdb/objc-exp.y create mode 100644 contrib/gdb-7/gdb/ppc-ravenscar-thread.c copy contrib/gdb-7/gdb/{common/xml-utils.h => ppc-ravenscar-thread.h} (69%) create mode 100644 contrib/gdb-7/gdb/probe.c create mode 100644 contrib/gdb-7/gdb/probe.h create mode 100644 contrib/gdb-7/gdb/python/lib/gdb/command/explore.py create mode 100644 contrib/gdb-7/gdb/python/lib/gdb/command/type_printers.py copy contrib/gdb-7/gdb/python/lib/gdb/{command => function}/__init__.py (91%) create mode 100644 contrib/gdb-7/gdb/python/lib/gdb/function/strfns.py create mode 100644 contrib/gdb-7/gdb/python/py-arch.c create mode 100644 contrib/gdb-7/gdb/python/py-gdb-readline.c create mode 100644 contrib/gdb-7/gdb/record-btrace.c copy contrib/gdb-7/gdb/{record.c => record-full.c} (51%) copy contrib/gdb-7/gdb/{record.h => record-full.h} (60%) create mode 100644 contrib/gdb-7/gdb/regformats/i386/x32-avx-linux.dat create mode 100644 contrib/gdb-7/gdb/regformats/i386/x32-avx.dat create mode 100644 contrib/gdb-7/gdb/regformats/i386/x32-linux.dat create mode 100644 contrib/gdb-7/gdb/regformats/i386/x32.dat create mode 100644 contrib/gdb-7/gdb/registry.c create mode 100644 contrib/gdb-7/gdb/registry.h create mode 100644 contrib/gdb-7/gdb/remote-notif.c create mode 100644 contrib/gdb-7/gdb/remote-notif.h create mode 100644 contrib/gdb-7/gdb/somread.c rename contrib/gdb-7/gdb/{ravenscar-sparc-thread.c => sparc-ravenscar-thread.c} (85%) copy contrib/gdb-7/gdb/{gdb_vfork.h => sparc-ravenscar-thread.h} (73%) create mode 100644 contrib/gdb-7/gdb/stap-probe.c create mode 100644 contrib/gdb-7/gdb/stap-probe.h create mode 100644 contrib/gdb-7/gdb/stubs/ChangeLog create mode 100644 contrib/gdb-7/gdb/stubs/buildvms.com create mode 100644 contrib/gdb-7/gdb/stubs/i386-stub.c create mode 100644 contrib/gdb-7/gdb/stubs/ia64vms-stub.c create mode 100644 contrib/gdb-7/gdb/stubs/m32r-stub.c create mode 100644 contrib/gdb-7/gdb/stubs/m68k-stub.c create mode 100644 contrib/gdb-7/gdb/stubs/sh-stub.c create mode 100644 contrib/gdb-7/gdb/stubs/sparc-stub.c create mode 100644 contrib/gdb-7/gdb/utils.h delete mode 100644 contrib/gdb-7/gdb/wrapper.c delete mode 100644 contrib/gdb-7/gdb/wrapper.h create mode 100644 contrib/gdb-7/include/dwarf2.def create mode 100644 contrib/gdb-7/include/gdb/gdb-index.h create mode 100644 contrib/gdb-7/include/leb128.h create mode 100644 contrib/gdb-7/libiberty/dwarfnames.c create mode 100644 contrib/gdb-7/libiberty/simple-object-xcoff.c create mode 100644 contrib/gdb-7/libiberty/strnlen.c diff --git a/contrib/gdb-7/bfd/README b/contrib/gdb-7/bfd/README index fe6b6f33c1..5ecfd298be 100644 --- a/contrib/gdb-7/bfd/README +++ b/contrib/gdb-7/bfd/README @@ -47,3 +47,9 @@ gcc manual. Bug reports without patches will be remembered, but they may never get fixed until somebody volunteers to fix them. + +Copyright (C) 2012 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/contrib/gdb-7/bfd/archive.c b/contrib/gdb-7/bfd/archive.c index 3e333c7e89..8cc6bf2a27 100644 --- a/contrib/gdb-7/bfd/archive.c +++ b/contrib/gdb-7/bfd/archive.c @@ -1,7 +1,5 @@ /* BFD back-end for archive files (libraries). - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright 1990-2013 Free Software Foundation, Inc. Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault. This file is part of BFD, the Binary File Descriptor library. @@ -42,11 +40,17 @@ DESCRIPTION have to read the entire archive if you don't want to! Read it until you find what you want. + A BFD returned by <> can be + closed manually with <>. If you do not close it, + then a second iteration through the members of an archive may + return the same BFD. If you close the archive BFD, then all + the member BFDs will automatically be closed as well. + Archive contents of output BFDs are chained through the - <> pointer in a BFD. The first one is findable through - the <> slot of the archive. Set it with - <> (q.v.). A given BFD may be in only one - open output archive at a time. + <> pointer in a BFD. The first one is findable + through the <> slot of the archive. Set it with + <> (q.v.). A given BFD may be in only + one open output archive at a time. As expected, the BFD archive code is more general than the archive code of any given environment. BFD archives may @@ -147,7 +151,8 @@ extern int errno; it's generally short enough to search linearly. Note that the pointers here point to the front of the ar_hdr, not to the front of the contents! */ -struct ar_cache { +struct ar_cache +{ file_ptr ptr; bfd *arbfd; }; @@ -168,6 +173,7 @@ _bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val) { static char buf[20]; size_t len; + snprintf (buf, sizeof (buf), fmt, val); len = strlen (buf); if (len < n) @@ -178,6 +184,29 @@ _bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val) else memcpy (p, buf, n); } + +bfd_boolean +_bfd_ar_sizepad (char *p, size_t n, bfd_size_type size) +{ + static char buf[21]; + size_t len; + + snprintf (buf, sizeof (buf), "%-10" BFD_VMA_FMT "u", size); + len = strlen (buf); + if (len > n) + { + bfd_set_error (bfd_error_file_too_big); + return FALSE; + } + if (len < n) + { + memcpy (p, buf, len); + memset (p + len, ' ', n - len); + } + else + memcpy (p, buf, n); + return TRUE; +} bfd_boolean _bfd_generic_mkarchive (bfd *abfd) @@ -273,6 +302,7 @@ _bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos) { htab_t hash_table = bfd_ardata (arch_bfd)->cache; struct ar_cache m; + m.ptr = filepos; if (hash_table) @@ -288,7 +318,7 @@ _bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos) } static hashval_t -hash_file_ptr (const PTR p) +hash_file_ptr (const void * p) { return (hashval_t) (((struct ar_cache *) p)->ptr); } @@ -296,7 +326,7 @@ hash_file_ptr (const PTR p) /* Returns non-zero if P1 and P2 are equal. */ static int -eq_file_ptr (const PTR p1, const PTR p2) +eq_file_ptr (const void * p1, const void * p2) { struct ar_cache *arc1 = (struct ar_cache *) p1; struct ar_cache *arc2 = (struct ar_cache *) p2; @@ -336,6 +366,10 @@ _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt) cache->arbfd = new_elt; *htab_find_slot (hash_table, (const void *) cache, INSERT) = cache; + /* Provide a means of accessing this from child. */ + arch_eltdata (new_elt)->parent_cache = hash_table; + arch_eltdata (new_elt)->key = filepos; + return TRUE; } @@ -345,12 +379,19 @@ _bfd_find_nested_archive (bfd *arch_bfd, const char *filename) bfd *abfd; const char *target; + /* PR 15140: Don't allow a nested archive pointing to itself. */ + if (filename_cmp (filename, arch_bfd->filename) == 0) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + for (abfd = arch_bfd->nested_archives; abfd != NULL; abfd = abfd->archive_next) { if (filename_cmp (filename, abfd->filename) == 0) - return abfd; + return abfd; } target = NULL; if (!arch_bfd->target_defaulted) @@ -390,10 +431,10 @@ get_extended_arelt_filename (bfd *arch, const char *name, file_ptr *originp) file_ptr origin = strtol (endp + 1, NULL, 10); if (errno != 0) - { - bfd_set_error (bfd_error_malformed_archive); - return NULL; - } + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } *originp = origin; } else @@ -424,7 +465,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) { struct ar_hdr hdr; char *hdrp = (char *) &hdr; - size_t parsed_size; + bfd_size_type parsed_size; struct areltdata *ared; char *filename = NULL; bfd_size_type namelen = 0; @@ -432,6 +473,8 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) char *allocptr = 0; file_ptr origin = 0; unsigned int extra_size = 0; + char fmag_save; + int scan; if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr)) { @@ -448,8 +491,11 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) } errno = 0; - parsed_size = strtol (hdr.ar_size, NULL, 10); - if (errno != 0) + fmag_save = hdr.ar_fmag[0]; + hdr.ar_fmag[0] = 0; + scan = sscanf (hdr.ar_size, "%" BFD_VMA_FMT "u", &parsed_size); + hdr.ar_fmag[0] = fmag_save; + if (scan != 1) { bfd_set_error (bfd_error_malformed_archive); return NULL; @@ -476,7 +522,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) parsed_size -= namelen; extra_size = namelen; - allocptr = (char *) bfd_zalloc (abfd, allocsize); + allocptr = (char *) bfd_zmalloc (allocsize); if (allocptr == NULL) return NULL; filename = (allocptr @@ -484,6 +530,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) + sizeof (struct ar_hdr)); if (bfd_bread (filename, namelen, abfd) != namelen) { + free (allocptr); if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_no_more_archived_files); return NULL; @@ -519,7 +566,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) if (!allocptr) { - allocptr = (char *) bfd_zalloc (abfd, allocsize); + allocptr = (char *) bfd_zmalloc (allocsize); if (allocptr == NULL) return NULL; } @@ -581,12 +628,6 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) bfd *n_nfd; char *filename; - if (archive->my_archive) - { - filepos += archive->origin; - archive = archive->my_archive; - } - n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos); if (n_nfd) return n_nfd; @@ -605,35 +646,38 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) /* This is a proxy entry for an external file. */ if (! IS_ABSOLUTE_PATH (filename)) - { - filename = _bfd_append_relative_path (archive, filename); - if (filename == NULL) - return NULL; - } + { + filename = _bfd_append_relative_path (archive, filename); + if (filename == NULL) + { + free (new_areldata); + return NULL; + } + } if (new_areldata->origin > 0) - { - /* This proxy entry refers to an element of a nested archive. - Locate the member of that archive and return a bfd for it. */ - bfd *ext_arch = _bfd_find_nested_archive (archive, filename); - - if (ext_arch == NULL - || ! bfd_check_format (ext_arch, bfd_archive)) - { - bfd_release (archive, new_areldata); - return NULL; - } - n_nfd = _bfd_get_elt_at_filepos (ext_arch, new_areldata->origin); - if (n_nfd == NULL) - { - bfd_release (archive, new_areldata); - return NULL; - } - n_nfd->proxy_origin = bfd_tell (archive); - return n_nfd; - } + { + /* This proxy entry refers to an element of a nested archive. + Locate the member of that archive and return a bfd for it. */ + bfd *ext_arch = _bfd_find_nested_archive (archive, filename); + + if (ext_arch == NULL + || ! bfd_check_format (ext_arch, bfd_archive)) + { + free (new_areldata); + return NULL; + } + n_nfd = _bfd_get_elt_at_filepos (ext_arch, new_areldata->origin); + if (n_nfd == NULL) + { + free (new_areldata); + return NULL; + } + n_nfd->proxy_origin = bfd_tell (archive); + return n_nfd; + } /* It's not an element of a nested archive; - open the external file as a bfd. */ + open the external file as a bfd. */ target = NULL; if (!archive->target_defaulted) target = archive->xvec->name; @@ -648,7 +692,7 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) if (n_nfd == NULL) { - bfd_release (archive, new_areldata); + free (new_areldata); return NULL; } @@ -672,7 +716,8 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd)) return n_nfd; - bfd_release (archive, new_areldata); + free (new_areldata); + n_nfd->arelt_data = NULL; return NULL; } @@ -727,13 +772,11 @@ bfd_generic_openr_next_archived_file (bfd *archive, bfd *last_file) filestart = bfd_ardata (archive)->first_file_filepos; else { - unsigned int size = arelt_size (last_file); + bfd_size_type size = arelt_size (last_file); filestart = last_file->proxy_origin; if (! bfd_is_thin_archive (archive)) - filestart += size; - if (archive->my_archive) - filestart -= archive->origin; + filestart += size; /* Pad to an even boundary... Note that last_file->origin can be odd in the case of BSD-4.4-style element with a long odd size. */ @@ -814,11 +857,7 @@ bfd_generic_archive_p (bfd *abfd) first->target_defaulted = FALSE; if (bfd_check_format (first, bfd_object) && first->xvec != abfd->xvec) - { - bfd_set_error (bfd_error_wrong_object_format); - bfd_ardata (abfd) = tdata_hold; - return NULL; - } + bfd_set_error (bfd_error_wrong_object_format); /* And we ought to close `first' here too. */ } } @@ -861,7 +900,7 @@ do_slurp_bsd_armap (bfd *abfd) if (mapdata == NULL) return FALSE; parsed_size = mapdata->parsed_size; - bfd_release (abfd, mapdata); /* Don't need it any more. */ + free (mapdata); raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size); if (raw_armap == NULL) @@ -925,7 +964,7 @@ do_slurp_coff_armap (bfd *abfd) struct artdata *ardata = bfd_ardata (abfd); char *stringbase; bfd_size_type stringsize; - unsigned int parsed_size; + bfd_size_type parsed_size; carsym *carsyms; bfd_size_type nsymz; /* Number of symbols in armap. */ bfd_vma (*swap) (const void *); @@ -937,7 +976,7 @@ do_slurp_coff_armap (bfd *abfd) if (mapdata == NULL) return FALSE; parsed_size = mapdata->parsed_size; - bfd_release (abfd, mapdata); /* Don't need it any more. */ + free (mapdata); if (bfd_bread (int_buf, 4, abfd) != 4) { @@ -979,7 +1018,7 @@ do_slurp_coff_armap (bfd *abfd) return FALSE; ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, - carsym_size + stringsize + 1); + carsym_size + stringsize + 1); if (ardata->symdefs == NULL) return FALSE; carsyms = ardata->symdefs; @@ -1030,7 +1069,7 @@ do_slurp_coff_armap (bfd *abfd) ardata->first_file_filepos += (tmp->parsed_size + sizeof (struct ar_hdr) + 1) & ~(unsigned) 1; } - bfd_release (abfd, tmp); + free (tmp); } } @@ -1079,21 +1118,21 @@ bfd_slurp_armap (bfd *abfd) else if (CONST_STRNEQ (nextname, "#1/20 ")) { /* Mach-O has a special name for armap when the map is sorted by name. - However because this name has a space it is slightly more difficult - to check it. */ + However because this name has a space it is slightly more difficult + to check it. */ struct ar_hdr hdr; char extname[21]; if (bfd_bread (&hdr, sizeof (hdr), abfd) != sizeof (hdr)) - return FALSE; + return FALSE; /* Read the extended name. We know its length. */ if (bfd_bread (extname, 20, abfd) != 20) - return FALSE; - if (bfd_seek (abfd, (file_ptr) -(sizeof (hdr) + 20), SEEK_CUR) != 0) - return FALSE; + return FALSE; + if (bfd_seek (abfd, -(file_ptr) (sizeof (hdr) + 20), SEEK_CUR) != 0) + return FALSE; if (CONST_STRNEQ (extname, "__.SYMDEF SORTED") - || CONST_STRNEQ (extname, "__.SYMDEF")) - return do_slurp_bsd_armap (abfd); + || CONST_STRNEQ (extname, "__.SYMDEF")) + return do_slurp_bsd_armap (abfd); } bfd_has_map (abfd) = FALSE; @@ -1147,15 +1186,17 @@ bfd_slurp_bsd_armap_f2 (bfd *abfd) if (mapdata->parsed_size < HPUX_SYMDEF_COUNT_SIZE + BSD_STRING_COUNT_SIZE) { + free (mapdata); wrong_format: bfd_set_error (bfd_error_wrong_format); byebye: - bfd_release (abfd, mapdata); return FALSE; } left = mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE - BSD_STRING_COUNT_SIZE; amt = mapdata->parsed_size; + free (mapdata); + raw_armap = (bfd_byte *) bfd_zalloc (abfd, amt); if (raw_armap == NULL) goto byebye; @@ -1250,14 +1291,14 @@ _bfd_slurp_extended_name_table (bfd *abfd) amt = namedata->parsed_size; if (amt + 1 == 0) - goto byebye; + goto byebye; bfd_ardata (abfd)->extended_names_size = amt; bfd_ardata (abfd)->extended_names = (char *) bfd_zalloc (abfd, amt + 1); if (bfd_ardata (abfd)->extended_names == NULL) { byebye: - bfd_release (abfd, namedata); + free (namedata); return FALSE; } @@ -1276,7 +1317,7 @@ _bfd_slurp_extended_name_table (bfd *abfd) trailing '/'. DOS/NT created archive often have \ in them We'll fix all problems here.. */ { - char *ext_names = bfd_ardata (abfd)->extended_names; + char *ext_names = bfd_ardata (abfd)->extended_names; char *temp = ext_names; char *limit = temp + namedata->parsed_size; for (; temp < limit; ++temp) @@ -1294,8 +1335,7 @@ _bfd_slurp_extended_name_table (bfd *abfd) bfd_ardata (abfd)->first_file_filepos += (bfd_ardata (abfd)->first_file_filepos) % 2; - /* FIXME, we can't release namedata here because it was allocated - below extended_names on the objalloc... */ + free (namedata); } return TRUE; } @@ -1366,7 +1406,7 @@ normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file) the autogenerated bfd.h header... Note - the string is returned in a static buffer. */ - + static const char * adjust_relative_path (const char * path, const char * ref_path) { @@ -1389,7 +1429,7 @@ adjust_relative_path (const char * path, const char * ref_path) rpath = lrealpath (ref_path); refp = rpath == NULL ? ref_path : rpath; - + /* Remove common leading path elements. */ for (;;) { @@ -1415,7 +1455,7 @@ adjust_relative_path (const char * path, const char * ref_path) { /* PR 12710: If the path element is "../" then instead of inserting "../" we need to insert the name of the directory - at the current level. */ + at the current level. */ if (refp > ref_path + 1 && refp[-1] == '.' && refp[-2] == '.') @@ -1426,7 +1466,7 @@ adjust_relative_path (const char * path, const char * ref_path) /* If the lrealpath calls above succeeded then we should never see dir_up and dir_down both being non-zero. */ - + len += 3 * dir_up; if (dir_down) @@ -1531,40 +1571,40 @@ _bfd_construct_extended_name_table (bfd *abfd, unsigned int thislen; if (bfd_is_thin_archive (abfd)) - { - const char *filename = current->filename; - - /* If the element being added is a member of another archive - (i.e., we are flattening), use the containing archive's name. */ - if (current->my_archive - && ! bfd_is_thin_archive (current->my_archive)) - filename = current->my_archive->filename; - - /* If the path is the same as the previous path seen, - reuse it. This can happen when flattening a thin - archive that contains other archives. */ - if (last_filename && filename_cmp (last_filename, filename) == 0) - continue; - - last_filename = filename; - - /* If the path is relative, adjust it relative to - the containing archive. */ - if (! IS_ABSOLUTE_PATH (filename) - && ! IS_ABSOLUTE_PATH (abfd->filename)) - normal = adjust_relative_path (filename, abfd->filename); - else - normal = filename; - - /* In a thin archive, always store the full pathname - in the extended name table. */ - total_namelen += strlen (normal) + 1; + { + const char *filename = current->filename; + + /* If the element being added is a member of another archive + (i.e., we are flattening), use the containing archive's name. */ + if (current->my_archive + && ! bfd_is_thin_archive (current->my_archive)) + filename = current->my_archive->filename; + + /* If the path is the same as the previous path seen, + reuse it. This can happen when flattening a thin + archive that contains other archives. */ + if (last_filename && filename_cmp (last_filename, filename) == 0) + continue; + + last_filename = filename; + + /* If the path is relative, adjust it relative to + the containing archive. */ + if (! IS_ABSOLUTE_PATH (filename) + && ! IS_ABSOLUTE_PATH (abfd->filename)) + normal = adjust_relative_path (filename, abfd->filename); + else + normal = filename; + + /* In a thin archive, always store the full pathname + in the extended name table. */ + total_namelen += strlen (normal) + 1; if (trailing_slash) /* Leave room for trailing slash. */ ++total_namelen; - continue; - } + continue; + } normal = normalize (current, current->filename); if (normal == NULL) @@ -1594,7 +1634,7 @@ _bfd_construct_extended_name_table (bfd *abfd, && hdr->ar_name[thislen] != ar_padchar (current))) { /* Must have been using extended format even though it - didn't need to. Fix it to use normal format. */ + didn't need to. Fix it to use normal format. */ memcpy (hdr->ar_name, normal, thislen); if (thislen < maxname || (thislen == maxname && thislen < sizeof hdr->ar_name)) @@ -1626,31 +1666,31 @@ _bfd_construct_extended_name_table (bfd *abfd, const char *filename = current->filename; if (bfd_is_thin_archive (abfd)) - { - /* If the element being added is a member of another archive - (i.e., we are flattening), use the containing archive's name. */ - if (current->my_archive - && ! bfd_is_thin_archive (current->my_archive)) - filename = current->my_archive->filename; - /* If the path is the same as the previous path seen, - reuse it. This can happen when flattening a thin - archive that contains other archives. - If the path is relative, adjust it relative to - the containing archive. */ - if (last_filename && filename_cmp (last_filename, filename) == 0) - normal = last_filename; - else if (! IS_ABSOLUTE_PATH (filename) - && ! IS_ABSOLUTE_PATH (abfd->filename)) - normal = adjust_relative_path (filename, abfd->filename); - else - normal = filename; - } + { + /* If the element being added is a member of another archive + (i.e., we are flattening), use the containing archive's name. */ + if (current->my_archive + && ! bfd_is_thin_archive (current->my_archive)) + filename = current->my_archive->filename; + /* If the path is the same as the previous path seen, + reuse it. This can happen when flattening a thin + archive that contains other archives. + If the path is relative, adjust it relative to + the containing archive. */ + if (last_filename && filename_cmp (last_filename, filename) == 0) + normal = last_filename; + else if (! IS_ABSOLUTE_PATH (filename) + && ! IS_ABSOLUTE_PATH (abfd->filename)) + normal = adjust_relative_path (filename, abfd->filename); + else + normal = filename; + } else - { - normal = normalize (current, filename); - if (normal == NULL) - return FALSE; - } + { + normal = normalize (current, filename); + if (normal == NULL) + return FALSE; + } thislen = strlen (normal); if (thislen > maxname || bfd_is_thin_archive (abfd)) @@ -1661,16 +1701,16 @@ _bfd_construct_extended_name_table (bfd *abfd, struct ar_hdr *hdr = arch_hdr (current); if (normal == last_filename) stroff = last_stroff; - else - { + else + { strcpy (strptr, normal); if (! trailing_slash) - strptr[thislen] = ARFMAG[1]; + strptr[thislen] = ARFMAG[1]; else - { - strptr[thislen] = '/'; - strptr[thislen + 1] = ARFMAG[1]; - } + { + strptr[thislen] = '/'; + strptr[thislen + 1] = ARFMAG[1]; + } stroff = strptr - *tabloc; last_stroff = stroff; } @@ -1678,19 +1718,19 @@ _bfd_construct_extended_name_table (bfd *abfd, if (bfd_is_thin_archive (abfd) && current->origin > 0) { int len = snprintf (hdr->ar_name + 1, maxname - 1, "%-ld:", - stroff); + stroff); _bfd_ar_spacepad (hdr->ar_name + 1 + len, maxname - 1 - len, - "%-ld", - current->origin - sizeof (struct ar_hdr)); + "%-ld", + current->origin - sizeof (struct ar_hdr)); } else - _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld", stroff); - if (normal != last_filename) - { + _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld", stroff); + if (normal != last_filename) + { strptr += thislen + 1; if (trailing_slash) - ++strptr; - last_filename = filename; + ++strptr; + last_filename = filename; } } } @@ -1703,9 +1743,9 @@ _bfd_construct_extended_name_table (bfd *abfd, bfd_boolean _bfd_archive_bsd44_construct_extended_name_table (bfd *abfd, - char **tabloc, - bfd_size_type *tablen, - const char **name) + char **tabloc, + bfd_size_type *tablen, + const char **name) { unsigned int maxname = ar_maxnamelen (abfd); bfd *current; @@ -1726,16 +1766,16 @@ _bfd_archive_bsd44_construct_extended_name_table (bfd *abfd, return FALSE; for (len = 0; normal[len]; len++) - if (normal[len] == ' ') - has_space = 1; + if (normal[len] == ' ') + has_space = 1; if (len > maxname || has_space) { - struct ar_hdr *hdr = arch_hdr (current); + struct ar_hdr *hdr = arch_hdr (current); - len = (len + 3) & ~3; - arch_eltdata (current)->extra_size = len; - _bfd_ar_spacepad (hdr->ar_name, maxname, "#1/%lu", len); + len = (len + 3) & ~3; + arch_eltdata (current)->extra_size = len; + _bfd_ar_spacepad (hdr->ar_name, maxname, "#1/%lu", len); } } @@ -1770,27 +1810,29 @@ _bfd_bsd44_write_ar_hdr (bfd *archive, bfd *abfd) BFD_ASSERT (padded_len == arch_eltdata (abfd)->extra_size); - _bfd_ar_spacepad (hdr->ar_size, sizeof (hdr->ar_size), "%-10ld", - arch_eltdata (abfd)->parsed_size + padded_len); + if (!_bfd_ar_sizepad (hdr->ar_size, sizeof (hdr->ar_size), + arch_eltdata (abfd)->parsed_size + padded_len)) + return FALSE; if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr)) - return FALSE; + return FALSE; if (bfd_bwrite (fullname, len, archive) != len) - return FALSE; + return FALSE; + if (len & 3) - { - static const char pad[3] = { 0, 0, 0 }; + { + static const char pad[3] = { 0, 0, 0 }; - len = 4 - (len & 3); - if (bfd_bwrite (pad, len, archive) != len) - return FALSE; - } + len = 4 - (len & 3); + if (bfd_bwrite (pad, len, archive) != len) + return FALSE; + } } else { if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr)) - return FALSE; + return FALSE; } return TRUE; } @@ -1861,7 +1903,7 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) } amt = sizeof (struct ar_hdr) + sizeof (struct areltdata); - ared = (struct areltdata *) bfd_zalloc (abfd, amt); + ared = (struct areltdata *) bfd_zmalloc (amt); if (ared == NULL) return NULL; hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata)); @@ -1870,7 +1912,7 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) memset (hdr, ' ', sizeof (struct ar_hdr)); _bfd_ar_spacepad (hdr->ar_date, sizeof (hdr->ar_date), "%-12ld", - status.st_mtime); + status.st_mtime); #ifdef HPUX_LARGE_AR_IDS /* HP has a very "special" way to handle UID/GID's with numeric values > 99999. */ @@ -1879,7 +1921,7 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) else #endif _bfd_ar_spacepad (hdr->ar_uid, sizeof (hdr->ar_uid), "%ld", - status.st_uid); + status.st_uid); #ifdef HPUX_LARGE_AR_IDS /* HP has a very "special" way to handle UID/GID's with numeric values > 99999. */ @@ -1888,11 +1930,14 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) else #endif _bfd_ar_spacepad (hdr->ar_gid, sizeof (hdr->ar_gid), "%ld", - status.st_gid); + status.st_gid); _bfd_ar_spacepad (hdr->ar_mode, sizeof (hdr->ar_mode), "%-8lo", - status.st_mode); - _bfd_ar_spacepad (hdr->ar_size, sizeof (hdr->ar_size), "%-10ld", - status.st_size); + status.st_mode); + if (!_bfd_ar_sizepad (hdr->ar_size, sizeof (hdr->ar_size), status.st_size)) + { + free (ared); + return NULL; + } memcpy (hdr->ar_fmag, ARFMAG, 2); ared->parsed_size = status.st_size; ared->arch_header = (char *) hdr; @@ -2132,8 +2177,9 @@ _bfd_write_archive_contents (bfd *arch) memset (&hdr, ' ', sizeof (struct ar_hdr)); memcpy (hdr.ar_name, ename, strlen (ename)); /* Round size up to even number in archive header. */ - _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", - (elength + 1) & ~(bfd_size_type) 1); + if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), + (elength + 1) & ~(bfd_size_type) 1)) + return FALSE; memcpy (hdr.ar_fmag, ARFMAG, 2); if ((bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) != sizeof (struct ar_hdr)) @@ -2151,13 +2197,13 @@ _bfd_write_archive_contents (bfd *arch) current = current->archive_next) { char buffer[DEFAULT_BUFFERSIZE]; - unsigned int remaining = arelt_size (current); + bfd_size_type remaining = arelt_size (current); /* Write ar header. */ if (!_bfd_write_ar_hdr (arch, current)) - return FALSE; + return FALSE; if (bfd_is_thin_archive (arch)) - continue; + continue; if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) goto input_err; @@ -2282,16 +2328,16 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) goto error_return; /* Now map over all the symbols, picking out the ones we - want. */ + want. */ for (src_count = 0; src_count < symcount; src_count++) { flagword flags = (syms[src_count])->flags; asection *sec = syms[src_count]->section; - if ((flags & BSF_GLOBAL - || flags & BSF_WEAK - || flags & BSF_INDIRECT - || flags & BSF_GNU_UNIQUE + if (((flags & (BSF_GLOBAL + | BSF_WEAK + | BSF_INDIRECT + | BSF_GNU_UNIQUE)) != 0 || bfd_is_com_section (sec)) && ! bfd_is_und_section (sec)) { @@ -2316,7 +2362,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) if (map[orl_count].name == NULL) goto error_return; *(map[orl_count].name) = (char *) bfd_alloc (arch, - namelen + 1); + namelen + 1); if (*(map[orl_count].name) == NULL) goto error_return; strcpy (*(map[orl_count].name), syms[src_count]->name); @@ -2406,10 +2452,11 @@ bsd_write_armap (bfd *arch, bfd_ardata (arch)->armap_datepos = (SARMAG + offsetof (struct ar_hdr, ar_date[0])); _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", - bfd_ardata (arch)->armap_timestamp); + bfd_ardata (arch)->armap_timestamp); _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", uid); _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", gid); - _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", mapsize); + if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) + return FALSE; memcpy (hdr.ar_fmag, ARFMAG, 2); if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) != sizeof (struct ar_hdr)) @@ -2420,22 +2467,33 @@ bsd_write_armap (bfd *arch, for (count = 0; count < orl_count; count++) { + unsigned int offset; bfd_byte buf[BSD_SYMDEF_SIZE]; if (map[count].u.abfd != last_elt) { do { - struct areltdata *ared = arch_eltdata (current); + struct areltdata *ared = arch_eltdata (current); firstreal += (ared->parsed_size + ared->extra_size - + sizeof (struct ar_hdr)); + + sizeof (struct ar_hdr)); firstreal += firstreal % 2; current = current->archive_next; } while (current != map[count].u.abfd); } + /* The archive file format only has 4 bytes to store the offset + of the member. Check to make sure that firstreal has not grown + too big. */ + offset = (unsigned int) firstreal; + if (firstreal != (file_ptr) offset) + { + bfd_set_error (bfd_error_file_truncated); + return FALSE; + } + last_elt = current; H_PUT_32 (arch, map[count].namidx, buf); H_PUT_32 (arch, firstreal, buf + BSD_SYMDEF_OFFSET_SIZE); @@ -2503,7 +2561,7 @@ _bfd_archive_bsd_update_armap_timestamp (bfd *arch) /* Prepare an ASCII version suitable for writing. */ memset (hdr.ar_date, ' ', sizeof (hdr.ar_date)); _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", - bfd_ardata (arch)->armap_timestamp); + bfd_ardata (arch)->armap_timestamp); /* Write it into the file. */ bfd_ardata (arch)->armap_datepos = (SARMAG @@ -2547,7 +2605,7 @@ coff_write_armap (bfd *arch, unsigned int ranlibsize = (symbol_count * 4) + 4; unsigned int stringsize = stridx; unsigned int mapsize = stringsize + ranlibsize; - unsigned int archive_member_file_ptr; + file_ptr archive_member_file_ptr; bfd *current = arch->archive_head; unsigned int count; struct ar_hdr hdr; @@ -2564,11 +2622,11 @@ coff_write_armap (bfd *arch, memset (&hdr, ' ', sizeof (struct ar_hdr)); hdr.ar_name[0] = '/'; - _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", - mapsize); + if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) + return FALSE; _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", - ((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0 - ? time (NULL) : 0)); + ((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0 + ? time (NULL) : 0)); /* This, at least, is what Intel coff sets the values to. */ _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0); _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0); @@ -2598,18 +2656,26 @@ coff_write_armap (bfd *arch, while (count < symbol_count && map[count].u.abfd == current) { - if (!bfd_write_bigendian_4byte_int (arch, archive_member_file_ptr)) + unsigned int offset = (unsigned int) archive_member_file_ptr; + + /* Catch an attempt to grow an archive past its 4Gb limit. */ + if (archive_member_file_ptr != (file_ptr) offset) + { + bfd_set_error (bfd_error_file_truncated); + return FALSE; + } + if (!bfd_write_bigendian_4byte_int (arch, offset)) return FALSE; count++; } archive_member_file_ptr += sizeof (struct ar_hdr); if (! bfd_is_thin_archive (arch)) - { - /* Add size of this archive entry. */ - archive_member_file_ptr += arelt_size (current); - /* Remember about the even alignment. */ - archive_member_file_ptr += archive_member_file_ptr % 2; - } + { + /* Add size of this archive entry. */ + archive_member_file_ptr += arelt_size (current); + /* Remember about the even alignment. */ + archive_member_file_ptr += archive_member_file_ptr % 2; + } current = current->archive_next; } @@ -2632,3 +2698,58 @@ coff_write_armap (bfd *arch, return TRUE; } + +static int +archive_close_worker (void **slot, void *inf ATTRIBUTE_UNUSED) +{ + struct ar_cache *ent = (struct ar_cache *) *slot; + + bfd_close_all_done (ent->arbfd); + return 1; +} + +bfd_boolean +_bfd_archive_close_and_cleanup (bfd *abfd) +{ + if (bfd_read_p (abfd) && abfd->format == bfd_archive) + { + bfd *nbfd; + bfd *next; + htab_t htab; + + /* Close nested archives (if this bfd is a thin archive). */ + for (nbfd = abfd->nested_archives; nbfd; nbfd = next) + { + next = nbfd->archive_next; + bfd_close (nbfd); + } + + htab = bfd_ardata (abfd)->cache; + if (htab) + { + htab_traverse_noresize (htab, archive_close_worker, NULL); + htab_delete (htab); + bfd_ardata (abfd)->cache = NULL; + } + } + else if (arch_eltdata (abfd) != NULL) + { + struct areltdata *ared = arch_eltdata (abfd); + htab_t htab = (htab_t) ared->parent_cache; + + if (htab) + { + struct ar_cache ent; + void **slot; + + ent.ptr = ared->key; + slot = htab_find_slot (htab, &ent, NO_INSERT); + if (slot != NULL) + { + BFD_ASSERT (((struct ar_cache *) *slot)->arbfd == abfd); + htab_clear_slot (htab, slot); + } + } + } + return TRUE; +} diff --git a/contrib/gdb-7/bfd/archive64.c b/contrib/gdb-7/bfd/archive64.c index bbc4c3f72f..be64e0d373 100644 --- a/contrib/gdb-7/bfd/archive64.c +++ b/contrib/gdb-7/bfd/archive64.c @@ -1,6 +1,5 @@ -/* MIPS-specific support for 64-bit ELF - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, - 2010 Free Software Foundation, Inc. +/* Support for 64-bit ELF archives. + Copyright 1996-2013 Free Software Foundation, Inc. Ian Lance Taylor, Cygnus Support Linker support added by Mark Mitchell, CodeSourcery, LLC. @@ -77,7 +76,7 @@ bfd_elf64_archive_slurp_armap (bfd *abfd) if (mapdata == NULL) return FALSE; parsed_size = mapdata->parsed_size; - bfd_release (abfd, mapdata); + free (mapdata); if (bfd_bread (int_buf, 8, abfd) != 8) { @@ -169,8 +168,8 @@ bfd_elf64_archive_write_armap (bfd *arch, memset (&hdr, ' ', sizeof (struct ar_hdr)); memcpy (hdr.ar_name, "/SYM64/", strlen ("/SYM64/")); - _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", - mapsize); + if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) + return FALSE; _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", time (NULL)); /* This, at least, is what Intel coff sets the values to.: */ @@ -200,7 +199,7 @@ bfd_elf64_archive_write_armap (bfd *arch, current = current->archive_next) { /* For each symbol which is used defined in this object, write out - the object file's address in the archive */ + the object file's address in the archive. */ for (; count < symbol_count && map[count].u.abfd == current; @@ -210,9 +209,11 @@ bfd_elf64_archive_write_armap (bfd *arch, if (bfd_bwrite (buf, 8, arch) != 8) return FALSE; } + /* Add size of this archive entry */ - archive_member_file_ptr += (arelt_size (current) - + sizeof (struct ar_hdr)); + archive_member_file_ptr += sizeof (struct ar_hdr); + if (! bfd_is_thin_archive (arch)) + archive_member_file_ptr += arelt_size (current); /* remember about the even alignment */ archive_member_file_ptr += archive_member_file_ptr % 2; } diff --git a/contrib/gdb-7/bfd/archures.c b/contrib/gdb-7/bfd/archures.c index f609534900..0be72da528 100644 --- a/contrib/gdb-7/bfd/archures.c +++ b/contrib/gdb-7/bfd/archures.c @@ -1,7 +1,7 @@ /* BFD library support routines for architectures. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012, 2013 Free Software Foundation, Inc. Hacked by John Gilmore and Steve Chamberlain of Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -145,7 +145,7 @@ DESCRIPTION .#define bfd_mach_sparc_64bit_p(mach) \ . ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) . bfd_arch_spu, {* PowerPC SPU *} -.#define bfd_mach_spu 256 +.#define bfd_mach_spu 256 . bfd_arch_mips, {* MIPS Rxxxx *} .#define bfd_mach_mips3000 3000 .#define bfd_mach_mips3900 3900 @@ -161,6 +161,7 @@ DESCRIPTION .#define bfd_mach_mips5000 5000 .#define bfd_mach_mips5400 5400 .#define bfd_mach_mips5500 5500 +.#define bfd_mach_mips5900 5900 .#define bfd_mach_mips6000 6000 .#define bfd_mach_mips7000 7000 .#define bfd_mach_mips8000 8000 @@ -241,7 +242,10 @@ DESCRIPTION .#define bfd_mach_ppc_e500 500 .#define bfd_mach_ppc_e500mc 5001 .#define bfd_mach_ppc_e500mc64 5005 +.#define bfd_mach_ppc_e5500 5006 +.#define bfd_mach_ppc_e6500 5007 .#define bfd_mach_ppc_titan 83 +.#define bfd_mach_ppc_vle 84 . bfd_arch_rs6000, {* IBM RS/6000 *} .#define bfd_mach_rs6k 6000 .#define bfd_mach_rs6k_rs1 6001 @@ -263,6 +267,8 @@ DESCRIPTION .#define bfd_mach_m6812_default 0 .#define bfd_mach_m6812 1 .#define bfd_mach_m6812s 2 +. bfd_arch_m9s12x, {* Freescale S12X *} +. bfd_arch_m9s12xg, {* Freescale XGATE *} . bfd_arch_z8k, {* Zilog Z8000 *} .#define bfd_mach_z8001 1 .#define bfd_mach_z8002 2 @@ -318,11 +324,13 @@ DESCRIPTION . bfd_arch_tic6x, {* Texas Instruments TMS320C6X *} . bfd_arch_tic80, {* TI TMS320c80 (MVP) *} . bfd_arch_v850, {* NEC V850 *} +. bfd_arch_v850_rh850,{* NEC V850 (using RH850 ABI) *} .#define bfd_mach_v850 1 .#define bfd_mach_v850e 'E' .#define bfd_mach_v850e1 '1' .#define bfd_mach_v850e2 0x4532 .#define bfd_mach_v850e2v3 0x45325633 +.#define bfd_mach_v850e3v5 0x45335635 {* ('E'|'3'|'V'|'5') *} . bfd_arch_arc, {* ARC Cores *} .#define bfd_mach_arc_5 5 .#define bfd_mach_arc_6 6 @@ -358,6 +366,8 @@ DESCRIPTION .#define bfd_mach_mep 1 .#define bfd_mach_mep_h1 0x6831 .#define bfd_mach_mep_c5 0x6335 +. bfd_arch_metag, +.#define bfd_mach_metag 1 . bfd_arch_ia64, {* HP/Intel ia64 *} .#define bfd_mach_ia64_elf64 64 .#define bfd_mach_ia64_elf32 32 @@ -412,7 +422,7 @@ DESCRIPTION . bfd_arch_s390, {* IBM s390 *} .#define bfd_mach_s390_31 31 .#define bfd_mach_s390_64 64 -. bfd_arch_score, {* Sunplus score *} +. bfd_arch_score, {* Sunplus score *} .#define bfd_mach_score3 3 .#define bfd_mach_score7 7 . bfd_arch_openrisc, {* OpenRISC *} @@ -438,7 +448,9 @@ DESCRIPTION . bfd_arch_xc16x, {* Infineon's XC16X Series. *} .#define bfd_mach_xc16x 1 .#define bfd_mach_xc16xl 2 -.#define bfd_mach_xc16xs 3 +.#define bfd_mach_xc16xs 3 +. bfd_arch_xgate, {* Freescale XGATE *} +.#define bfd_mach_xgate 1 . bfd_arch_xtensa, {* Tensilica's Xtensa cores. *} .#define bfd_mach_xtensa 1 . bfd_arch_z80, @@ -453,6 +465,11 @@ DESCRIPTION . bfd_arch_tilegx, {* Tilera TILE-Gx *} .#define bfd_mach_tilepro 1 .#define bfd_mach_tilegx 1 +.#define bfd_mach_tilegx32 2 +. bfd_arch_aarch64, {* AArch64 *} +.#define bfd_mach_aarch64 0 +. bfd_arch_nios2, +.#define bfd_mach_nios2 0 . bfd_arch_last . }; */ @@ -485,12 +502,19 @@ DESCRIPTION . . bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); . +. {* Allocate via bfd_malloc and return a fill buffer of size COUNT. If +. IS_BIGENDIAN is TRUE, the order of bytes is big endian. If CODE is +. TRUE, the buffer contains code. *} +. void *(*fill) (bfd_size_type count, bfd_boolean is_bigendian, +. bfd_boolean code); +. . const struct bfd_arch_info *next; .} .bfd_arch_info_type; . */ +extern const bfd_arch_info_type bfd_aarch64_arch; extern const bfd_arch_info_type bfd_alpha_arch; extern const bfd_arch_info_type bfd_arc_arch; extern const bfd_arch_info_type bfd_arm_arch; @@ -523,10 +547,13 @@ extern const bfd_arch_info_type bfd_m32c_arch; extern const bfd_arch_info_type bfd_m32r_arch; extern const bfd_arch_info_type bfd_m68hc11_arch; extern const bfd_arch_info_type bfd_m68hc12_arch; +extern const bfd_arch_info_type bfd_m9s12x_arch; +extern const bfd_arch_info_type bfd_m9s12xg_arch; extern const bfd_arch_info_type bfd_m68k_arch; extern const bfd_arch_info_type bfd_m88k_arch; extern const bfd_arch_info_type bfd_mcore_arch; extern const bfd_arch_info_type bfd_mep_arch; +extern const bfd_arch_info_type bfd_metag_arch; extern const bfd_arch_info_type bfd_mips_arch; extern const bfd_arch_info_type bfd_microblaze_arch; extern const bfd_arch_info_type bfd_mmix_arch; @@ -535,6 +562,7 @@ extern const bfd_arch_info_type bfd_mn10300_arch; extern const bfd_arch_info_type bfd_moxie_arch; extern const bfd_arch_info_type bfd_msp430_arch; extern const bfd_arch_info_type bfd_mt_arch; +extern const bfd_arch_info_type bfd_nios2_arch; extern const bfd_arch_info_type bfd_ns32k_arch; extern const bfd_arch_info_type bfd_openrisc_arch; extern const bfd_arch_info_type bfd_or32_arch; @@ -559,12 +587,14 @@ extern const bfd_arch_info_type bfd_tic80_arch; extern const bfd_arch_info_type bfd_tilegx_arch; extern const bfd_arch_info_type bfd_tilepro_arch; extern const bfd_arch_info_type bfd_v850_arch; +extern const bfd_arch_info_type bfd_v850_rh850_arch; extern const bfd_arch_info_type bfd_vax_arch; extern const bfd_arch_info_type bfd_w65_arch; extern const bfd_arch_info_type bfd_we32k_arch; extern const bfd_arch_info_type bfd_xstormy16_arch; extern const bfd_arch_info_type bfd_xtensa_arch; extern const bfd_arch_info_type bfd_xc16x_arch; +extern const bfd_arch_info_type bfd_xgate_arch; extern const bfd_arch_info_type bfd_z80_arch; extern const bfd_arch_info_type bfd_z8k_arch; @@ -573,6 +603,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = #ifdef SELECT_ARCHITECTURES SELECT_ARCHITECTURES, #else + &bfd_aarch64_arch, &bfd_alpha_arch, &bfd_arc_arch, &bfd_arm_arch, @@ -605,10 +636,13 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_m32r_arch, &bfd_m68hc11_arch, &bfd_m68hc12_arch, + &bfd_m9s12x_arch, + &bfd_m9s12xg_arch, &bfd_m68k_arch, &bfd_m88k_arch, &bfd_mcore_arch, &bfd_mep_arch, + &bfd_metag_arch, &bfd_microblaze_arch, &bfd_mips_arch, &bfd_mmix_arch, @@ -617,6 +651,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_moxie_arch, &bfd_msp430_arch, &bfd_mt_arch, + &bfd_nios2_arch, &bfd_ns32k_arch, &bfd_openrisc_arch, &bfd_or32_arch, @@ -638,12 +673,14 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_tilegx_arch, &bfd_tilepro_arch, &bfd_v850_arch, + &bfd_v850_rh850_arch, &bfd_vax_arch, &bfd_w65_arch, &bfd_we32k_arch, &bfd_xstormy16_arch, &bfd_xtensa_arch, &bfd_xc16x_arch, + &bfd_xgate_arch, &bfd_z80_arch, &bfd_z8k_arch, #endif @@ -814,6 +851,7 @@ const bfd_arch_info_type bfd_default_arch_struct = { 32, 32, 8, bfd_arch_unknown, 0, "unknown", "unknown", 2, TRUE, bfd_default_compatible, bfd_default_scan, + bfd_arch_default_fill, 0, }; @@ -1309,3 +1347,29 @@ bfd_arch_mach_octets_per_byte (enum bfd_architecture arch, return ap->bits_per_byte / 8; return 1; } + +/* +INTERNAL_FUNCTION + bfd_arch_default_fill + +SYNOPSIS + void *bfd_arch_default_fill (bfd_size_type count, + bfd_boolean is_bigendian, + bfd_boolean code); + +DESCRIPTION + Allocate via bfd_malloc and return a fill buffer of size COUNT. + If IS_BIGENDIAN is TRUE, the order of bytes is big endian. If + CODE is TRUE, the buffer contains code. +*/ + +void * +bfd_arch_default_fill (bfd_size_type count, + bfd_boolean is_bigendian ATTRIBUTE_UNUSED, + bfd_boolean code ATTRIBUTE_UNUSED) +{ + void *fill = bfd_malloc (count); + if (fill != NULL) + memset (fill, 0, count); + return fill; +} diff --git a/contrib/gdb-7/bfd/bfd-in.h b/contrib/gdb-7/bfd/bfd-in.h index 40ed786628..1d51932568 100644 --- a/contrib/gdb-7/bfd/bfd-in.h +++ b/contrib/gdb-7/bfd/bfd-in.h @@ -1,8 +1,8 @@ /* Main header file for the bfd library -- portable access to object files. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Contributed by Cygnus Support. @@ -25,6 +25,11 @@ #ifndef __BFD_H_SEEN__ #define __BFD_H_SEEN__ +/* PR 14072: Ensure that config.h is included first. */ +#if !defined PACKAGE && !defined PACKAGE_VERSION +#error config.h must be included before this header +#endif + #ifdef __cplusplus extern "C" { #endif @@ -57,7 +62,7 @@ extern "C" { problem for example when trying to use STRING_COMMA_LEN to build the arguments to the strncmp() macro. Hence this alternative definition of strncmp is provided here. - + Note - these macros do NOT work if STR2 is not a constant string. */ #define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) /* strcpy() can have a similar problem, but since we know we are @@ -273,18 +278,19 @@ alent; typedef struct bfd_section *sec_ptr; -#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) -#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) -#define bfd_get_section_lma(bfd, ptr) ((ptr)->lma + 0) -#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_get_section_name(bfd, ptr) ((void) bfd, (ptr)->name) +#define bfd_get_section_vma(bfd, ptr) ((void) bfd, (ptr)->vma) +#define bfd_get_section_lma(bfd, ptr) ((void) bfd, (ptr)->lma) +#define bfd_get_section_alignment(bfd, ptr) ((void) bfd, \ + (ptr)->alignment_power) #define bfd_section_name(bfd, ptr) ((ptr)->name) #define bfd_section_size(bfd, ptr) ((ptr)->size) #define bfd_get_section_size(ptr) ((ptr)->size) #define bfd_section_vma(bfd, ptr) ((ptr)->vma) #define bfd_section_lma(bfd, ptr) ((ptr)->lma) #define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) -#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) -#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) +#define bfd_get_section_flags(bfd, ptr) ((void) bfd, (ptr)->flags) +#define bfd_get_section_userdata(bfd, ptr) ((void) bfd, (ptr)->userdata) #define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) @@ -297,11 +303,11 @@ typedef struct bfd_section *sec_ptr; ? (sec)->rawsize : (sec)->size) / bfd_octets_per_byte (bfd)) /* Return TRUE if input section SEC has been discarded. */ -#define elf_discarded_section(sec) \ +#define discarded_section(sec) \ (!bfd_is_abs_section (sec) \ && bfd_is_abs_section ((sec)->output_section) \ - && (sec)->sec_info_type != ELF_INFO_TYPE_MERGE \ - && (sec)->sec_info_type != ELF_INFO_TYPE_JUST_SYMS) + && (sec)->sec_info_type != SEC_INFO_TYPE_MERGE \ + && (sec)->sec_info_type != SEC_INFO_TYPE_JUST_SYMS) typedef enum bfd_print_symbol { @@ -642,6 +648,8 @@ extern struct bfd_link_needed_list *bfd_elf_get_needed_list (bfd *, struct bfd_link_info *); extern bfd_boolean bfd_elf_get_bfd_needed_list (bfd *, struct bfd_link_needed_list **); +extern bfd_boolean bfd_elf_stack_segment_size (bfd *, struct bfd_link_info *, + const char *, bfd_vma); extern bfd_boolean bfd_elf_size_dynamic_sections (bfd *, const char *, const char *, const char *, const char *, const char *, const char * const *, struct bfd_link_info *, struct bfd_section **); @@ -692,19 +700,15 @@ extern int bfd_get_elf_phdrs the remote memory. */ extern bfd *bfd_elf_bfd_from_remote_memory (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); - -/* Return the arch_size field of an elf bfd, or -1 if not elf. */ -extern int bfd_get_arch_size - (bfd *); - -/* Return TRUE if address "naturally" sign extends, or -1 if not elf. */ -extern int bfd_get_sign_extend_vma - (bfd *); + int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, + bfd_size_type len)); extern struct bfd_section *_bfd_elf_tls_setup (bfd *, struct bfd_link_info *); +extern struct bfd_section * +_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma); + extern void _bfd_fix_excluded_sec_syms (bfd *, struct bfd_link_info *); @@ -926,6 +930,32 @@ extern unsigned int _bfd_elf_ppc_at_tls_transform extern unsigned int _bfd_elf_ppc_at_tprel_transform (unsigned int, unsigned int); +extern void bfd_elf64_aarch64_init_maps + (bfd *); + +void bfd_elf64_aarch64_set_options + (bfd *, struct bfd_link_info *, int, int, int); + +/* ELF AArch64 mapping symbol support. */ +#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0) +#define BFD_AARCH64_SPECIAL_SYM_TYPE_TAG (1 << 1) +#define BFD_AARCH64_SPECIAL_SYM_TYPE_OTHER (1 << 2) +#define BFD_AARCH64_SPECIAL_SYM_TYPE_ANY (~0) +extern bfd_boolean bfd_is_aarch64_special_symbol_name + (const char * name, int type); + +/* AArch64 stub generation support. Called from the linker. */ +extern int elf64_aarch64_setup_section_lists + (bfd *, struct bfd_link_info *); +extern void elf64_aarch64_next_input_section + (struct bfd_link_info *, struct bfd_section *); +extern bfd_boolean elf64_aarch64_size_stubs + (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, + struct bfd_section * (*) (const char *, struct bfd_section *), + void (*) (void)); +extern bfd_boolean elf64_aarch64_build_stubs + (struct bfd_link_info *); + /* TI COFF load page support. */ extern void bfd_ticoff_set_section_load_page (struct bfd_section *, int); diff --git a/contrib/gdb-7/bfd/bfd-in2.h b/contrib/gdb-7/bfd/bfd-in2.h index 2bb0ec7db5..524e97e78b 100644 --- a/contrib/gdb-7/bfd/bfd-in2.h +++ b/contrib/gdb-7/bfd/bfd-in2.h @@ -8,8 +8,8 @@ /* Main header file for the bfd library -- portable access to object files. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Contributed by Cygnus Support. @@ -32,6 +32,11 @@ #ifndef __BFD_H_SEEN__ #define __BFD_H_SEEN__ +/* PR 14072: Ensure that config.h is included first. */ +#if !defined PACKAGE && !defined PACKAGE_VERSION +#error config.h must be included before this header +#endif + #ifdef __cplusplus extern "C" { #endif @@ -64,7 +69,7 @@ extern "C" { problem for example when trying to use STRING_COMMA_LEN to build the arguments to the strncmp() macro. Hence this alternative definition of strncmp is provided here. - + Note - these macros do NOT work if STR2 is not a constant string. */ #define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) /* strcpy() can have a similar problem, but since we know we are @@ -280,18 +285,19 @@ alent; typedef struct bfd_section *sec_ptr; -#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) -#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) -#define bfd_get_section_lma(bfd, ptr) ((ptr)->lma + 0) -#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_get_section_name(bfd, ptr) ((void) bfd, (ptr)->name) +#define bfd_get_section_vma(bfd, ptr) ((void) bfd, (ptr)->vma) +#define bfd_get_section_lma(bfd, ptr) ((void) bfd, (ptr)->lma) +#define bfd_get_section_alignment(bfd, ptr) ((void) bfd, \ + (ptr)->alignment_power) #define bfd_section_name(bfd, ptr) ((ptr)->name) #define bfd_section_size(bfd, ptr) ((ptr)->size) #define bfd_get_section_size(ptr) ((ptr)->size) #define bfd_section_vma(bfd, ptr) ((ptr)->vma) #define bfd_section_lma(bfd, ptr) ((ptr)->lma) #define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) -#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) -#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) +#define bfd_get_section_flags(bfd, ptr) ((void) bfd, (ptr)->flags) +#define bfd_get_section_userdata(bfd, ptr) ((void) bfd, (ptr)->userdata) #define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) @@ -304,11 +310,11 @@ typedef struct bfd_section *sec_ptr; ? (sec)->rawsize : (sec)->size) / bfd_octets_per_byte (bfd)) /* Return TRUE if input section SEC has been discarded. */ -#define elf_discarded_section(sec) \ +#define discarded_section(sec) \ (!bfd_is_abs_section (sec) \ && bfd_is_abs_section ((sec)->output_section) \ - && (sec)->sec_info_type != ELF_INFO_TYPE_MERGE \ - && (sec)->sec_info_type != ELF_INFO_TYPE_JUST_SYMS) + && (sec)->sec_info_type != SEC_INFO_TYPE_MERGE \ + && (sec)->sec_info_type != SEC_INFO_TYPE_JUST_SYMS) typedef enum bfd_print_symbol { @@ -649,6 +655,8 @@ extern struct bfd_link_needed_list *bfd_elf_get_needed_list (bfd *, struct bfd_link_info *); extern bfd_boolean bfd_elf_get_bfd_needed_list (bfd *, struct bfd_link_needed_list **); +extern bfd_boolean bfd_elf_stack_segment_size (bfd *, struct bfd_link_info *, + const char *, bfd_vma); extern bfd_boolean bfd_elf_size_dynamic_sections (bfd *, const char *, const char *, const char *, const char *, const char *, const char * const *, struct bfd_link_info *, struct bfd_section **); @@ -699,19 +707,15 @@ extern int bfd_get_elf_phdrs the remote memory. */ extern bfd *bfd_elf_bfd_from_remote_memory (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); - -/* Return the arch_size field of an elf bfd, or -1 if not elf. */ -extern int bfd_get_arch_size - (bfd *); - -/* Return TRUE if address "naturally" sign extends, or -1 if not elf. */ -extern int bfd_get_sign_extend_vma - (bfd *); + int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, + bfd_size_type len)); extern struct bfd_section *_bfd_elf_tls_setup (bfd *, struct bfd_link_info *); +extern struct bfd_section * +_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma); + extern void _bfd_fix_excluded_sec_syms (bfd *, struct bfd_link_info *); @@ -933,6 +937,32 @@ extern unsigned int _bfd_elf_ppc_at_tls_transform extern unsigned int _bfd_elf_ppc_at_tprel_transform (unsigned int, unsigned int); +extern void bfd_elf64_aarch64_init_maps + (bfd *); + +void bfd_elf64_aarch64_set_options + (bfd *, struct bfd_link_info *, int, int, int); + +/* ELF AArch64 mapping symbol support. */ +#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0) +#define BFD_AARCH64_SPECIAL_SYM_TYPE_TAG (1 << 1) +#define BFD_AARCH64_SPECIAL_SYM_TYPE_OTHER (1 << 2) +#define BFD_AARCH64_SPECIAL_SYM_TYPE_ANY (~0) +extern bfd_boolean bfd_is_aarch64_special_symbol_name + (const char * name, int type); + +/* AArch64 stub generation support. Called from the linker. */ +extern int elf64_aarch64_setup_section_lists + (bfd *, struct bfd_link_info *); +extern void elf64_aarch64_next_input_section + (struct bfd_link_info *, struct bfd_section *); +extern bfd_boolean elf64_aarch64_size_stubs + (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, + struct bfd_section * (*) (const char *, struct bfd_section *), + void (*) (void)); +extern bfd_boolean elf64_aarch64_build_stubs + (struct bfd_link_info *); + /* TI COFF load page support. */ extern void bfd_ticoff_set_section_load_page (struct bfd_section *, int); @@ -1383,11 +1413,11 @@ typedef struct bfd_section /* Type of sec_info information. */ unsigned int sec_info_type:3; -#define ELF_INFO_TYPE_NONE 0 -#define ELF_INFO_TYPE_STABS 1 -#define ELF_INFO_TYPE_MERGE 2 -#define ELF_INFO_TYPE_EH_FRAME 3 -#define ELF_INFO_TYPE_JUST_SYMS 4 +#define SEC_INFO_TYPE_NONE 0 +#define SEC_INFO_TYPE_STABS 1 +#define SEC_INFO_TYPE_MERGE 2 +#define SEC_INFO_TYPE_EH_FRAME 3 +#define SEC_INFO_TYPE_JUST_SYMS 4 /* Nonzero if this section uses RELA relocations, rather than REL. */ unsigned int use_rela_p:1; @@ -1517,9 +1547,6 @@ typedef struct bfd_section /* The BFD which owns the section. */ bfd *owner; - /* INPUT_SECTION_FLAGS if specified in the linker script. */ - struct flag_info *section_flag_info; - /* A symbol which points at this section only. */ struct bfd_symbol *symbol; struct bfd_symbol **symbol_ptr_ptr; @@ -1535,40 +1562,37 @@ typedef struct bfd_section } asection; /* Relax table contains information about instructions which can - be removed by relaxation -- replacing a long address with a + be removed by relaxation -- replacing a long address with a short address. */ struct relax_table { /* Address where bytes may be deleted. */ bfd_vma addr; - + /* Number of bytes to be deleted. */ int size; }; /* These sections are global, and are managed by BFD. The application and target back end are not permitted to change the values in - these sections. New code should use the section_ptr macros rather - than referring directly to the const sections. The const sections - may eventually vanish. */ + these sections. */ +extern asection _bfd_std_section[4]; + #define BFD_ABS_SECTION_NAME "*ABS*" #define BFD_UND_SECTION_NAME "*UND*" #define BFD_COM_SECTION_NAME "*COM*" #define BFD_IND_SECTION_NAME "*IND*" -/* The absolute section. */ -extern asection bfd_abs_section; -#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) -#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) -/* Pointer to the undefined section. */ -extern asection bfd_und_section; -#define bfd_und_section_ptr ((asection *) &bfd_und_section) -#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) /* Pointer to the common section. */ -extern asection bfd_com_section; -#define bfd_com_section_ptr ((asection *) &bfd_com_section) +#define bfd_com_section_ptr (&_bfd_std_section[0]) +/* Pointer to the undefined section. */ +#define bfd_und_section_ptr (&_bfd_std_section[1]) +/* Pointer to the absolute section. */ +#define bfd_abs_section_ptr (&_bfd_std_section[2]) /* Pointer to the indirect section. */ -extern asection bfd_ind_section; -#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) +#define bfd_ind_section_ptr (&_bfd_std_section[3]) + +#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) +#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) #define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) #define bfd_is_const_section(SEC) \ @@ -1683,8 +1707,8 @@ extern asection bfd_ind_section; /* vma, lma, size, rawsize, compressed_size, relax, relax_count, */ \ 0, 0, 0, 0, 0, 0, 0, \ \ - /* output_offset, output_section, alignment_power, */ \ - 0, (struct bfd_section *) &SEC, 0, \ + /* output_offset, output_section, alignment_power, */ \ + 0, &SEC, 0, \ \ /* relocation, orelocation, reloc_count, filepos, rel_filepos, */ \ NULL, NULL, 0, 0, 0, \ @@ -1698,9 +1722,6 @@ extern asection bfd_ind_section; /* target_index, used_by_bfd, constructor_chain, owner, */ \ 0, NULL, NULL, NULL, \ \ - /* flag_info, */ \ - NULL, \ - \ /* symbol, symbol_ptr_ptr, */ \ (struct bfd_symbol *) SYM, &SEC.symbol, \ \ @@ -1712,6 +1733,10 @@ void bfd_section_list_clear (bfd *); asection *bfd_get_section_by_name (bfd *abfd, const char *name); +asection *bfd_get_next_section_by_name (asection *sec); + +asection *bfd_get_linker_section (bfd *abfd, const char *name); + asection *bfd_get_section_by_name_if (bfd *abfd, const char *name, @@ -1851,7 +1876,7 @@ enum bfd_architecture #define bfd_mach_sparc_64bit_p(mach) \ ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) bfd_arch_spu, /* PowerPC SPU */ -#define bfd_mach_spu 256 +#define bfd_mach_spu 256 bfd_arch_mips, /* MIPS Rxxxx */ #define bfd_mach_mips3000 3000 #define bfd_mach_mips3900 3900 @@ -1867,6 +1892,7 @@ enum bfd_architecture #define bfd_mach_mips5000 5000 #define bfd_mach_mips5400 5400 #define bfd_mach_mips5500 5500 +#define bfd_mach_mips5900 5900 #define bfd_mach_mips6000 6000 #define bfd_mach_mips7000 7000 #define bfd_mach_mips8000 8000 @@ -1947,7 +1973,10 @@ enum bfd_architecture #define bfd_mach_ppc_e500 500 #define bfd_mach_ppc_e500mc 5001 #define bfd_mach_ppc_e500mc64 5005 +#define bfd_mach_ppc_e5500 5006 +#define bfd_mach_ppc_e6500 5007 #define bfd_mach_ppc_titan 83 +#define bfd_mach_ppc_vle 84 bfd_arch_rs6000, /* IBM RS/6000 */ #define bfd_mach_rs6k 6000 #define bfd_mach_rs6k_rs1 6001 @@ -1969,6 +1998,8 @@ enum bfd_architecture #define bfd_mach_m6812_default 0 #define bfd_mach_m6812 1 #define bfd_mach_m6812s 2 + bfd_arch_m9s12x, /* Freescale S12X */ + bfd_arch_m9s12xg, /* Freescale XGATE */ bfd_arch_z8k, /* Zilog Z8000 */ #define bfd_mach_z8001 1 #define bfd_mach_z8002 2 @@ -2024,11 +2055,13 @@ enum bfd_architecture bfd_arch_tic6x, /* Texas Instruments TMS320C6X */ bfd_arch_tic80, /* TI TMS320c80 (MVP) */ bfd_arch_v850, /* NEC V850 */ + bfd_arch_v850_rh850,/* NEC V850 (using RH850 ABI) */ #define bfd_mach_v850 1 #define bfd_mach_v850e 'E' #define bfd_mach_v850e1 '1' #define bfd_mach_v850e2 0x4532 #define bfd_mach_v850e2v3 0x45325633 +#define bfd_mach_v850e3v5 0x45335635 /* ('E'|'3'|'V'|'5') */ bfd_arch_arc, /* ARC Cores */ #define bfd_mach_arc_5 5 #define bfd_mach_arc_6 6 @@ -2064,6 +2097,8 @@ enum bfd_architecture #define bfd_mach_mep 1 #define bfd_mach_mep_h1 0x6831 #define bfd_mach_mep_c5 0x6335 + bfd_arch_metag, +#define bfd_mach_metag 1 bfd_arch_ia64, /* HP/Intel ia64 */ #define bfd_mach_ia64_elf64 64 #define bfd_mach_ia64_elf32 32 @@ -2118,7 +2153,7 @@ enum bfd_architecture bfd_arch_s390, /* IBM s390 */ #define bfd_mach_s390_31 31 #define bfd_mach_s390_64 64 - bfd_arch_score, /* Sunplus score */ + bfd_arch_score, /* Sunplus score */ #define bfd_mach_score3 3 #define bfd_mach_score7 7 bfd_arch_openrisc, /* OpenRISC */ @@ -2144,7 +2179,9 @@ enum bfd_architecture bfd_arch_xc16x, /* Infineon's XC16X Series. */ #define bfd_mach_xc16x 1 #define bfd_mach_xc16xl 2 -#define bfd_mach_xc16xs 3 +#define bfd_mach_xc16xs 3 + bfd_arch_xgate, /* Freescale XGATE */ +#define bfd_mach_xgate 1 bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ #define bfd_mach_xtensa 1 bfd_arch_z80, @@ -2159,6 +2196,11 @@ enum bfd_architecture bfd_arch_tilegx, /* Tilera TILE-Gx */ #define bfd_mach_tilepro 1 #define bfd_mach_tilegx 1 +#define bfd_mach_tilegx32 2 + bfd_arch_aarch64, /* AArch64 */ +#define bfd_mach_aarch64 0 + bfd_arch_nios2, +#define bfd_mach_nios2 0 bfd_arch_last }; @@ -2181,6 +2223,12 @@ typedef struct bfd_arch_info bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); + /* Allocate via bfd_malloc and return a fill buffer of size COUNT. If + IS_BIGENDIAN is TRUE, the order of bytes is big endian. If CODE is + TRUE, the buffer contains code. */ + void *(*fill) (bfd_size_type count, bfd_boolean is_bigendian, + bfd_boolean code); + const struct bfd_arch_info *next; } bfd_arch_info_type; @@ -2478,6 +2526,10 @@ The 24-bit relocation is used in some Intel 960 configurations. */ BFD_RELOC_HI16_S_PLTOFF, BFD_RELOC_8_PLTOFF, +/* Size relocations. */ + BFD_RELOC_SIZE32, + BFD_RELOC_SIZE64, + /* Relocations used by 68K ELF. */ BFD_RELOC_68K_GLOB_DAT, BFD_RELOC_68K_JMP_SLOT, @@ -2591,6 +2643,10 @@ relocation types already defined. */ BFD_RELOC_SPARC_M44, BFD_RELOC_SPARC_L44, BFD_RELOC_SPARC_REGISTER, + BFD_RELOC_SPARC_H34, + BFD_RELOC_SPARC_SIZE32, + BFD_RELOC_SPARC_SIZE64, + BFD_RELOC_SPARC_WDISP10, /* SPARC little endian relocation */ BFD_RELOC_SPARC_REV32, @@ -2786,6 +2842,15 @@ to compensate for the borrow when the low bits are added. */ /* MIPS16 low 16 bits. */ BFD_RELOC_MIPS16_LO16, +/* MIPS16 TLS relocations */ + BFD_RELOC_MIPS16_TLS_GD, + BFD_RELOC_MIPS16_TLS_LDM, + BFD_RELOC_MIPS16_TLS_DTPREL_HI16, + BFD_RELOC_MIPS16_TLS_DTPREL_LO16, + BFD_RELOC_MIPS16_TLS_GOTTPREL, + BFD_RELOC_MIPS16_TLS_TPREL_HI16, + BFD_RELOC_MIPS16_TLS_TPREL_LO16, + /* Relocation against a MIPS literal section. */ BFD_RELOC_MIPS_LITERAL, BFD_RELOC_MICROMIPS_LITERAL, @@ -2947,6 +3012,25 @@ be honoured at the offset's location, regardless of linker relaxation. */ BFD_RELOC_MN10300_ALIGN, +/* Various TLS-related relocations. */ + BFD_RELOC_MN10300_TLS_GD, + BFD_RELOC_MN10300_TLS_LD, + BFD_RELOC_MN10300_TLS_LDO, + BFD_RELOC_MN10300_TLS_GOTIE, + BFD_RELOC_MN10300_TLS_IE, + BFD_RELOC_MN10300_TLS_LE, + BFD_RELOC_MN10300_TLS_DTPMOD, + BFD_RELOC_MN10300_TLS_DTPOFF, + BFD_RELOC_MN10300_TLS_TPOFF, + +/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. */ + BFD_RELOC_MN10300_32_PCREL, + +/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. */ + BFD_RELOC_MN10300_16_PCREL, + /* i386/elf relocations */ BFD_RELOC_386_GOT32, @@ -3060,6 +3144,23 @@ relaxation. */ BFD_RELOC_PPC_EMB_RELST_HA, BFD_RELOC_PPC_EMB_BIT_FLD, BFD_RELOC_PPC_EMB_RELSDA, + BFD_RELOC_PPC_VLE_REL8, + BFD_RELOC_PPC_VLE_REL15, + BFD_RELOC_PPC_VLE_REL24, + BFD_RELOC_PPC_VLE_LO16A, + BFD_RELOC_PPC_VLE_LO16D, + BFD_RELOC_PPC_VLE_HI16A, + BFD_RELOC_PPC_VLE_HI16D, + BFD_RELOC_PPC_VLE_HA16A, + BFD_RELOC_PPC_VLE_HA16D, + BFD_RELOC_PPC_VLE_SDA21, + BFD_RELOC_PPC_VLE_SDA21_LO, + BFD_RELOC_PPC_VLE_SDAREL_LO16A, + BFD_RELOC_PPC_VLE_SDAREL_LO16D, + BFD_RELOC_PPC_VLE_SDAREL_HI16A, + BFD_RELOC_PPC_VLE_SDAREL_HI16D, + BFD_RELOC_PPC_VLE_SDAREL_HA16A, + BFD_RELOC_PPC_VLE_SDAREL_HA16D, BFD_RELOC_PPC64_HIGHER, BFD_RELOC_PPC64_HIGHER_S, BFD_RELOC_PPC64_HIGHEST, @@ -3782,14 +3883,6 @@ instructions. */ /* start data in text. */ BFD_RELOC_V850_DATA, -/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the -instruction. */ - BFD_RELOC_MN10300_32_PCREL, - -/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the -instruction. */ - BFD_RELOC_MN10300_16_PCREL, - /* This is a 8bit DP reloc for the tms320c30, where the most significant 8 bits of a 24 bit word are placed into the least significant 8 bits of the opcode. */ @@ -3912,6 +4005,46 @@ short offset into 11 bits. */ BFD_RELOC_MEP_GNU_VTENTRY, +/* Imagination Technologies Meta relocations. */ + BFD_RELOC_METAG_HIADDR16, + BFD_RELOC_METAG_LOADDR16, + BFD_RELOC_METAG_RELBRANCH, + BFD_RELOC_METAG_GETSETOFF, + BFD_RELOC_METAG_HIOG, + BFD_RELOC_METAG_LOOG, + BFD_RELOC_METAG_REL8, + BFD_RELOC_METAG_REL16, + BFD_RELOC_METAG_HI16_GOTOFF, + BFD_RELOC_METAG_LO16_GOTOFF, + BFD_RELOC_METAG_GETSET_GOTOFF, + BFD_RELOC_METAG_GETSET_GOT, + BFD_RELOC_METAG_HI16_GOTPC, + BFD_RELOC_METAG_LO16_GOTPC, + BFD_RELOC_METAG_HI16_PLT, + BFD_RELOC_METAG_LO16_PLT, + BFD_RELOC_METAG_RELBRANCH_PLT, + BFD_RELOC_METAG_GOTOFF, + BFD_RELOC_METAG_PLT, + BFD_RELOC_METAG_COPY, + BFD_RELOC_METAG_JMP_SLOT, + BFD_RELOC_METAG_RELATIVE, + BFD_RELOC_METAG_GLOB_DAT, + BFD_RELOC_METAG_TLS_GD, + BFD_RELOC_METAG_TLS_LDM, + BFD_RELOC_METAG_TLS_LDO_HI16, + BFD_RELOC_METAG_TLS_LDO_LO16, + BFD_RELOC_METAG_TLS_LDO, + BFD_RELOC_METAG_TLS_IE, + BFD_RELOC_METAG_TLS_IENONPIC, + BFD_RELOC_METAG_TLS_IENONPIC_HI16, + BFD_RELOC_METAG_TLS_IENONPIC_LO16, + BFD_RELOC_METAG_TLS_TPOFF, + BFD_RELOC_METAG_TLS_DTPMOD, + BFD_RELOC_METAG_TLS_DTPOFF, + BFD_RELOC_METAG_TLS_LE, + BFD_RELOC_METAG_TLS_LE_HI16, + BFD_RELOC_METAG_TLS_LE_LO16, + /* These are relocations for the GETA instruction. */ BFD_RELOC_MMIX_GETA, BFD_RELOC_MMIX_GETA_1, @@ -4011,7 +4144,7 @@ of 32 bit value) into 8 bit immediate value of LDI insn. */ command address) into 8 bit immediate value of LDI insn. */ BFD_RELOC_AVR_LO8_LDI_PM, -/* This is a 16 bit reloc for the AVR that stores 8 bit value +/* This is a 16 bit reloc for the AVR that stores 8 bit value (command address) into 8 bit immediate value of LDI insn. If the address is beyond the 128k boundary, the linker inserts a jump stub for this reloc in the lower 128k. */ @@ -4061,6 +4194,18 @@ instructions */ instructions */ BFD_RELOC_AVR_6_ADIW, +/* This is a 8 bit reloc for the AVR that stores bits 0..7 of a symbol +in .byte lo8(symbol) */ + BFD_RELOC_AVR_8_LO, + +/* This is a 8 bit reloc for the AVR that stores bits 8..15 of a symbol +in .byte hi8(symbol) */ + BFD_RELOC_AVR_8_HI, + +/* This is a 8 bit reloc for the AVR that stores bits 16..23 of a symbol +in .byte hlo8(symbol) */ + BFD_RELOC_AVR_8_HLO, + /* Renesas RL78 Relocations. */ BFD_RELOC_RL78_NEG8, BFD_RELOC_RL78_NEG16, @@ -4094,6 +4239,7 @@ instructions */ BFD_RELOC_RL78_HI16, BFD_RELOC_RL78_HI8, BFD_RELOC_RL78_LO16, + BFD_RELOC_RL78_CODE, /* Renesas RX Relocations. */ BFD_RELOC_RX_NEG8, @@ -4230,6 +4376,9 @@ instructions */ BFD_RELOC_390_GOTPLT20, BFD_RELOC_390_TLS_GOTIE20, +/* STT_GNU_IFUNC relocation. */ + BFD_RELOC_390_IRELATIVE, + /* Score relocations Low 16 bit for load/store */ BFD_RELOC_SCORE_GPREL15, @@ -4444,6 +4593,83 @@ to follow the 16K memory bank of 68HC12 (seen as mapped in the window). */ This is the 5 bits of a value. */ BFD_RELOC_M68HC12_5B, +/* Freescale XGATE reloc. +This reloc marks the beginning of a bra/jal instruction. */ + BFD_RELOC_XGATE_RL_JUMP, + +/* Freescale XGATE reloc. +This reloc marks a group of several instructions that gcc generates +and for which the linker relaxation pass can modify and/or remove +some of them. */ + BFD_RELOC_XGATE_RL_GROUP, + +/* Freescale XGATE reloc. +This is the 16-bit lower part of an address. It is used for the '16-bit' +instructions. */ + BFD_RELOC_XGATE_LO16, + +/* Freescale XGATE reloc. */ + BFD_RELOC_XGATE_GPAGE, + +/* Freescale XGATE reloc. */ + BFD_RELOC_XGATE_24, + +/* Freescale XGATE reloc. +This is a 9-bit pc-relative reloc. */ + BFD_RELOC_XGATE_PCREL_9, + +/* Freescale XGATE reloc. +This is a 10-bit pc-relative reloc. */ + BFD_RELOC_XGATE_PCREL_10, + +/* Freescale XGATE reloc. +This is the 16-bit lower part of an address. It is used for the '16-bit' +instructions. */ + BFD_RELOC_XGATE_IMM8_LO, + +/* Freescale XGATE reloc. +This is the 16-bit higher part of an address. It is used for the '16-bit' +instructions. */ + BFD_RELOC_XGATE_IMM8_HI, + +/* Freescale XGATE reloc. +This is a 3-bit pc-relative reloc. */ + BFD_RELOC_XGATE_IMM3, + +/* Freescale XGATE reloc. +This is a 4-bit pc-relative reloc. */ + BFD_RELOC_XGATE_IMM4, + +/* Freescale XGATE reloc. +This is a 5-bit pc-relative reloc. */ + BFD_RELOC_XGATE_IMM5, + +/* Motorola 68HC12 reloc. +This is the 9 bits of a value. */ + BFD_RELOC_M68HC12_9B, + +/* Motorola 68HC12 reloc. +This is the 16 bits of a value. */ + BFD_RELOC_M68HC12_16B, + +/* Motorola 68HC12/XGATE reloc. +This is a PCREL9 branch. */ + BFD_RELOC_M68HC12_9_PCREL, + +/* Motorola 68HC12/XGATE reloc. +This is a PCREL10 branch. */ + BFD_RELOC_M68HC12_10_PCREL, + +/* Motorola 68HC12/XGATE reloc. +This is the 8 bit low part of an absolute address and immediately precedes +a matching HI8XG part. */ + BFD_RELOC_M68HC12_LO8XG, + +/* Motorola 68HC12/XGATE reloc. +This is the 8 bit high part of an absolute address and immediately follows +a matching LO8XG part. */ + BFD_RELOC_M68HC12_HI8XG, + /* NS CR16C Relocations. */ BFD_RELOC_16C_NUM08, BFD_RELOC_16C_NUM08_C, @@ -4690,6 +4916,42 @@ This is the 5 bits of a value. */ BFD_RELOC_MSP430_2X_PCREL, BFD_RELOC_MSP430_RL_PCREL, +/* Relocations used by the Altera Nios II core. */ + BFD_RELOC_NIOS2_S16, + BFD_RELOC_NIOS2_U16, + BFD_RELOC_NIOS2_CALL26, + BFD_RELOC_NIOS2_IMM5, + BFD_RELOC_NIOS2_CACHE_OPX, + BFD_RELOC_NIOS2_IMM6, + BFD_RELOC_NIOS2_IMM8, + BFD_RELOC_NIOS2_HI16, + BFD_RELOC_NIOS2_LO16, + BFD_RELOC_NIOS2_HIADJ16, + BFD_RELOC_NIOS2_GPREL, + BFD_RELOC_NIOS2_UJMP, + BFD_RELOC_NIOS2_CJMP, + BFD_RELOC_NIOS2_CALLR, + BFD_RELOC_NIOS2_ALIGN, + BFD_RELOC_NIOS2_GOT16, + BFD_RELOC_NIOS2_CALL16, + BFD_RELOC_NIOS2_GOTOFF_LO, + BFD_RELOC_NIOS2_GOTOFF_HA, + BFD_RELOC_NIOS2_PCREL_LO, + BFD_RELOC_NIOS2_PCREL_HA, + BFD_RELOC_NIOS2_TLS_GD16, + BFD_RELOC_NIOS2_TLS_LDM16, + BFD_RELOC_NIOS2_TLS_LDO16, + BFD_RELOC_NIOS2_TLS_IE16, + BFD_RELOC_NIOS2_TLS_LE16, + BFD_RELOC_NIOS2_TLS_DTPMOD, + BFD_RELOC_NIOS2_TLS_DTPREL, + BFD_RELOC_NIOS2_TLS_TPREL, + BFD_RELOC_NIOS2_COPY, + BFD_RELOC_NIOS2_GLOB_DAT, + BFD_RELOC_NIOS2_JUMP_SLOT, + BFD_RELOC_NIOS2_RELATIVE, + BFD_RELOC_NIOS2_GOTOFF, + /* IQ2000 Relocations. */ BFD_RELOC_IQ2000_OFFSET_16, BFD_RELOC_IQ2000_OFFSET_21, @@ -4810,6 +5072,9 @@ BFD_RELOC_XTENSA_ASM_EXPAND. */ BFD_RELOC_MACH_O_PAIR. */ BFD_RELOC_MACH_O_SECTDIFF, +/* Like BFD_RELOC_MACH_O_SECTDIFF but with a local symbol. */ + BFD_RELOC_MACH_O_LOCAL_SECTDIFF, + /* Pair of relocation. Contains the first symbol. */ BFD_RELOC_MACH_O_PAIR, @@ -4840,52 +5105,52 @@ the linker could optimize the movq to a leaq if possible. */ /* Same as BFD_RELOC_32_PCREL but with an implicit -4 addend. */ BFD_RELOC_MACH_O_X86_64_PCREL32_4, -/* This is a 32 bit reloc for the microblaze that stores the +/* This is a 32 bit reloc for the microblaze that stores the low 16 bits of a value */ BFD_RELOC_MICROBLAZE_32_LO, -/* This is a 32 bit pc-relative reloc for the microblaze that +/* This is a 32 bit pc-relative reloc for the microblaze that stores the low 16 bits of a value */ BFD_RELOC_MICROBLAZE_32_LO_PCREL, -/* This is a 32 bit reloc for the microblaze that stores a +/* This is a 32 bit reloc for the microblaze that stores a value relative to the read-only small data area anchor */ BFD_RELOC_MICROBLAZE_32_ROSDA, -/* This is a 32 bit reloc for the microblaze that stores a +/* This is a 32 bit reloc for the microblaze that stores a value relative to the read-write small data area anchor */ BFD_RELOC_MICROBLAZE_32_RWSDA, -/* This is a 32 bit reloc for the microblaze to handle +/* This is a 32 bit reloc for the microblaze to handle expressions of the form "Symbol Op Symbol" */ BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM, -/* This is a 64 bit reloc that stores the 32 bit pc relative -value in two words (with an imm instruction). No relocation is +/* This is a 64 bit reloc that stores the 32 bit pc relative +value in two words (with an imm instruction). No relocation is done here - only used for relaxing */ BFD_RELOC_MICROBLAZE_64_NONE, -/* This is a 64 bit reloc that stores the 32 bit pc relative +/* This is a 64 bit reloc that stores the 32 bit pc relative value in two words (with an imm instruction). The relocation is PC-relative GOT offset */ BFD_RELOC_MICROBLAZE_64_GOTPC, -/* This is a 64 bit reloc that stores the 32 bit pc relative +/* This is a 64 bit reloc that stores the 32 bit pc relative value in two words (with an imm instruction). The relocation is GOT offset */ BFD_RELOC_MICROBLAZE_64_GOT, -/* This is a 64 bit reloc that stores the 32 bit pc relative +/* This is a 64 bit reloc that stores the 32 bit pc relative value in two words (with an imm instruction). The relocation is PC-relative offset into PLT */ BFD_RELOC_MICROBLAZE_64_PLT, -/* This is a 64 bit reloc that stores the 32 bit GOT relative +/* This is a 64 bit reloc that stores the 32 bit GOT relative value in two words (with an imm instruction). The relocation is relative offset from _GLOBAL_OFFSET_TABLE_ */ BFD_RELOC_MICROBLAZE_64_GOTOFF, -/* This is a 32 bit reloc that stores the 32 bit GOT relative +/* This is a 32 bit reloc that stores the 32 bit GOT relative value in a word. The relocation is relative offset from */ BFD_RELOC_MICROBLAZE_32_GOTOFF, @@ -4893,6 +5158,258 @@ value in a word. The relocation is relative offset from */ the dynamic object into the runtime process image. */ BFD_RELOC_MICROBLAZE_COPY, +/* Unused Reloc */ + BFD_RELOC_MICROBLAZE_64_TLS, + +/* This is a 64 bit reloc that stores the 32 bit GOT relative value +of the GOT TLS GD info entry in two words (with an imm instruction). The +relocation is GOT offset. */ + BFD_RELOC_MICROBLAZE_64_TLSGD, + +/* This is a 64 bit reloc that stores the 32 bit GOT relative value +of the GOT TLS LD info entry in two words (with an imm instruction). The +relocation is GOT offset. */ + BFD_RELOC_MICROBLAZE_64_TLSLD, + +/* This is a 32 bit reloc that stores the Module ID to GOT(n). */ + BFD_RELOC_MICROBLAZE_32_TLSDTPMOD, + +/* This is a 32 bit reloc that stores TLS offset to GOT(n+1). */ + BFD_RELOC_MICROBLAZE_32_TLSDTPREL, + +/* This is a 32 bit reloc for storing TLS offset to two words (uses imm +instruction) */ + BFD_RELOC_MICROBLAZE_64_TLSDTPREL, + +/* This is a 64 bit reloc that stores 32-bit thread pointer relative offset +to two words (uses imm instruction). */ + BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL, + +/* This is a 64 bit reloc that stores 32-bit thread pointer relative offset +to two words (uses imm instruction). */ + BFD_RELOC_MICROBLAZE_64_TLSTPREL, + +/* AArch64 ADD immediate instruction, holding bits 0 to 11 of the address. +Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_ADD_LO12, + +/* AArch64 Load Literal instruction, holding a 19 bit PC relative word +offset of the global offset table entry for a symbol. The lowest two +bits must be zero and are not stored in the instruction, giving a 21 +bit signed byte offset. This relocation type requires signed overflow +checking. */ + BFD_RELOC_AARCH64_GOT_LD_PREL19, + +/* Get to the page base of the global offset table entry for a symbol as +part of an ADRP instruction using a 21 bit PC relative value.Used in +conjunction with BFD_RELOC_AARCH64_LD64_GOT_LO12_NC. */ + BFD_RELOC_AARCH64_ADR_GOT_PAGE, + +/* AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page +offset, giving a 4KB aligned page base address. */ + BFD_RELOC_AARCH64_ADR_HI21_PCREL, + +/* AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page +offset, giving a 4KB aligned page base address, but with no overflow +checking. */ + BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL, + +/* AArch64 ADR instruction, holding a simple 21 bit pc-relative byte offset. */ + BFD_RELOC_AARCH64_ADR_LO21_PCREL, + +/* AArch64 19 bit pc-relative conditional branch and compare & branch. +The lowest two bits must be zero and are not stored in the instruction, +giving a 21 bit signed byte offset. */ + BFD_RELOC_AARCH64_BRANCH19, + +/* AArch64 26 bit pc-relative unconditional branch and link. +The lowest two bits must be zero and are not stored in the instruction, +giving a 28 bit signed byte offset. */ + BFD_RELOC_AARCH64_CALL26, + +/* AArch64 pseudo relocation code to be used internally by the AArch64 +assembler and not (currently) written to any object files. */ + BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP, + +/* AArch64 26 bit pc-relative unconditional branch. +The lowest two bits must be zero and are not stored in the instruction, +giving a 28 bit signed byte offset. */ + BFD_RELOC_AARCH64_JUMP26, + +/* AArch64 Load Literal instruction, holding a 19 bit pc-relative word +offset. The lowest two bits must be zero and are not stored in the +instruction, giving a 21 bit signed byte offset. */ + BFD_RELOC_AARCH64_LD_LO19_PCREL, + +/* Unsigned 12 bit byte offset for 64 bit load/store from the page of +the GOT entry for this symbol. Used in conjunction with +BFD_RELOC_AARCH64_ADR_GOTPAGE. */ + BFD_RELOC_AARCH64_LD64_GOT_LO12_NC, + +/* AArch64 unspecified load/store instruction, holding bits 0 to 11 of the +address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_LDST_LO12, + +/* AArch64 8-bit load/store instruction, holding bits 0 to 11 of the +address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_LDST8_LO12, + +/* AArch64 16-bit load/store instruction, holding bits 0 to 11 of the +address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_LDST16_LO12, + +/* AArch64 32-bit load/store instruction, holding bits 0 to 11 of the +address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_LDST32_LO12, + +/* AArch64 64-bit load/store instruction, holding bits 0 to 11 of the +address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_LDST64_LO12, + +/* AArch64 128-bit load/store instruction, holding bits 0 to 11 of the +address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ + BFD_RELOC_AARCH64_LDST128_LO12, + +/* AArch64 MOV[NZK] instruction with most significant bits 0 to 15 +of an unsigned address/value. */ + BFD_RELOC_AARCH64_MOVW_G0, + +/* AArch64 MOV[NZ] instruction with most significant bits 0 to 15 +of a signed value. Changes instruction to MOVZ or MOVN depending on the +value's sign. */ + BFD_RELOC_AARCH64_MOVW_G0_S, + +/* AArch64 MOV[NZK] instruction with less significant bits 0 to 15 of +an address/value. No overflow checking. */ + BFD_RELOC_AARCH64_MOVW_G0_NC, + +/* AArch64 MOV[NZK] instruction with most significant bits 16 to 31 +of an unsigned address/value. */ + BFD_RELOC_AARCH64_MOVW_G1, + +/* AArch64 MOV[NZK] instruction with less significant bits 16 to 31 +of an address/value. No overflow checking. */ + BFD_RELOC_AARCH64_MOVW_G1_NC, + +/* AArch64 MOV[NZ] instruction with most significant bits 16 to 31 +of a signed value. Changes instruction to MOVZ or MOVN depending on the +value's sign. */ + BFD_RELOC_AARCH64_MOVW_G1_S, + +/* AArch64 MOV[NZK] instruction with most significant bits 32 to 47 +of an unsigned address/value. */ + BFD_RELOC_AARCH64_MOVW_G2, + +/* AArch64 MOV[NZK] instruction with less significant bits 32 to 47 +of an address/value. No overflow checking. */ + BFD_RELOC_AARCH64_MOVW_G2_NC, + +/* AArch64 MOV[NZ] instruction with most significant bits 32 to 47 +of a signed value. Changes instruction to MOVZ or MOVN depending on the +value's sign. */ + BFD_RELOC_AARCH64_MOVW_G2_S, + +/* AArch64 MOV[NZK] instruction with most signficant bits 48 to 64 +of a signed or unsigned address/value. */ + BFD_RELOC_AARCH64_MOVW_G3, + +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_TLSDESC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_ADD, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_CALL, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_LD64_PREL19, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_LDR, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC, + +/* AArch64 TLS DESC relocation. */ + BFD_RELOC_AARCH64_TLSDESC_OFF_G1, + +/* Unsigned 12 bit byte offset to global offset table entry for a symbols +tls_index structure. Used in conjunction with +BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21. */ + BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC, + +/* Get to the page base of the global offset table entry for a symbols +tls_index structure as part of an adrp instruction using a 21 bit PC +relative value. Used in conjunction with +BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC. */ + BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21, + +/* AArch64 TLS INITIAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, + +/* AArch64 TLS INITIAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19, + +/* AArch64 TLS INITIAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, + +/* AArch64 TLS INITIAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC, + +/* AArch64 TLS INITIAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1, + +/* AArch64 TLS LOCAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12, + +/* AArch64 TLS LOCAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12, + +/* AArch64 TLS LOCAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC, + +/* AArch64 TLS LOCAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0, + +/* AArch64 TLS LOCAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC, + +/* AArch64 TLS LOCAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1, + +/* AArch64 TLS LOCAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC, + +/* AArch64 TLS LOCAL EXEC relocation. */ + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2, + +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_TLS_DTPMOD64, + +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_TLS_DTPREL64, + +/* AArch64 TLS relocation. */ + BFD_RELOC_AARCH64_TLS_TPREL64, + +/* AArch64 14 bit pc-relative test bit and branch. +The lowest two bits must be zero and are not stored in the instruction, +giving a 16 bit signed byte offset. */ + BFD_RELOC_AARCH64_TSTBR14, + /* Tilera TILEPro Relocations. */ BFD_RELOC_TILEPRO_COPY, BFD_RELOC_TILEPRO_GLOB_DAT, @@ -4940,6 +5457,12 @@ the dynamic object into the runtime process image. */ BFD_RELOC_TILEPRO_SHAMT_X1, BFD_RELOC_TILEPRO_SHAMT_Y0, BFD_RELOC_TILEPRO_SHAMT_Y1, + BFD_RELOC_TILEPRO_TLS_GD_CALL, + BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD, + BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD, + BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD, + BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD, + BFD_RELOC_TILEPRO_TLS_IE_LOAD, BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD, BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD, BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO, @@ -4959,6 +5482,14 @@ the dynamic object into the runtime process image. */ BFD_RELOC_TILEPRO_TLS_DTPMOD32, BFD_RELOC_TILEPRO_TLS_DTPOFF32, BFD_RELOC_TILEPRO_TLS_TPOFF32, + BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE, + BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE, + BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO, + BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO, + BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI, + BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI, + BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA, + BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA, /* Tilera TILE-Gx Relocations. */ BFD_RELOC_TILEGX_HW0, @@ -5018,52 +5549,58 @@ the dynamic object into the runtime process image. */ BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PCREL, BFD_RELOC_TILEGX_IMM16_X0_HW0_GOT, BFD_RELOC_TILEGX_IMM16_X1_HW0_GOT, - BFD_RELOC_TILEGX_IMM16_X0_HW1_GOT, - BFD_RELOC_TILEGX_IMM16_X1_HW1_GOT, - BFD_RELOC_TILEGX_IMM16_X0_HW2_GOT, - BFD_RELOC_TILEGX_IMM16_X1_HW2_GOT, - BFD_RELOC_TILEGX_IMM16_X0_HW3_GOT, - BFD_RELOC_TILEGX_IMM16_X1_HW3_GOT, + BFD_RELOC_TILEGX_IMM16_X0_HW0_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X1_HW0_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X0_HW1_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X1_HW1_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X0_HW2_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X1_HW2_PLT_PCREL, BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_GOT, BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_GOT, BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_GOT, BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_GOT, - BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_GOT, - BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_GOT, + BFD_RELOC_TILEGX_IMM16_X0_HW3_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X1_HW3_PLT_PCREL, BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD, BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD, - BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_GD, - BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_GD, - BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_GD, - BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_GD, - BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_GD, - BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_GD, + BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE, + BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE, + BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE, + BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE, + BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE, + BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE, BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD, BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD, BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD, BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD, - BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_GD, - BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_GD, BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE, BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE, - BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_IE, - BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_IE, - BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_IE, - BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_IE, - BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_IE, - BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_IE, + BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL, + BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL, BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE, BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE, BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE, BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE, - BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_IE, - BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_IE, BFD_RELOC_TILEGX_TLS_DTPMOD64, BFD_RELOC_TILEGX_TLS_DTPOFF64, BFD_RELOC_TILEGX_TLS_TPOFF64, BFD_RELOC_TILEGX_TLS_DTPMOD32, BFD_RELOC_TILEGX_TLS_DTPOFF32, BFD_RELOC_TILEGX_TLS_TPOFF32, + BFD_RELOC_TILEGX_TLS_GD_CALL, + BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD, + BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD, + BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD, + BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD, + BFD_RELOC_TILEGX_TLS_IE_LOAD, + BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD, + BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD, + BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD, + BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD, /* Adapteva EPIPHANY - 8 bit signed pc-relative displacement */ BFD_RELOC_EPIPHANY_SIMM8, @@ -5600,6 +6137,15 @@ void bfd_set_error_program_name (const char *); bfd_error_handler_type bfd_get_error_handler (void); +typedef void (*bfd_assert_handler_type) (const char *bfd_formatmsg, + const char *bfd_version, + const char *bfd_file, + int bfd_line); + +bfd_assert_handler_type bfd_set_assert_handler (bfd_assert_handler_type); + +bfd_assert_handler_type bfd_get_assert_handler (void); + long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); long bfd_canonicalize_reloc @@ -5648,6 +6194,11 @@ bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); BFD_SEND (abfd, _bfd_find_nearest_line, \ (abfd, sec, syms, off, file, func, line)) +#define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \ + line, disc) \ + BFD_SEND (abfd, _bfd_find_nearest_line_discriminator, \ + (abfd, sec, syms, off, file, func, line, disc)) + #define bfd_find_line(abfd, syms, sym, file, line) \ BFD_SEND (abfd, _bfd_find_line, \ (abfd, syms, sym, file, line)) @@ -5680,8 +6231,8 @@ bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); #define bfd_gc_sections(abfd, link_info) \ BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) -#define bfd_lookup_section_flags(link_info, flag_info) \ - BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info)) +#define bfd_lookup_section_flags(link_info, flag_info, section) \ + BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info, section)) #define bfd_merge_sections(abfd, link_info) \ BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) @@ -5735,24 +6286,6 @@ extern bfd_byte *bfd_get_relocated_section_contents bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); -struct bfd_preserve -{ - void *marker; - void *tdata; - flagword flags; - const struct bfd_arch_info *arch_info; - struct bfd_section *sections; - struct bfd_section *section_last; - unsigned int section_count; - struct bfd_hash_table section_htab; -}; - -bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); - -void bfd_preserve_restore (bfd *, struct bfd_preserve *); - -void bfd_preserve_finish (bfd *, struct bfd_preserve *); - bfd_vma bfd_emul_get_maxpagesize (const char *); void bfd_emul_set_maxpagesize (const char *, bfd_vma); @@ -6029,6 +6562,7 @@ typedef struct bfd_target NAME##_bfd_is_target_special_symbol, \ NAME##_get_lineno, \ NAME##_find_nearest_line, \ + _bfd_generic_find_nearest_line_discriminator, \ _bfd_generic_find_line, \ NAME##_find_inliner_info, \ NAME##_bfd_make_debug_symbol, \ @@ -6052,6 +6586,9 @@ typedef struct bfd_target bfd_boolean (*_bfd_find_nearest_line) (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, const char **, const char **, unsigned int *); + bfd_boolean (*_bfd_find_nearest_line_discriminator) + (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, + const char **, const char **, unsigned int *, unsigned int *); bfd_boolean (*_bfd_find_line) (bfd *, struct bfd_symbol **, struct bfd_symbol *, const char **, unsigned int *); @@ -6157,8 +6694,9 @@ typedef struct bfd_target bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); /* Sets the bitmask of allowed and disallowed section flags. */ - void (*_bfd_lookup_section_flags) (struct bfd_link_info *, - struct flag_info *); + bfd_boolean (*_bfd_lookup_section_flags) (struct bfd_link_info *, + struct flag_info *, + asection *); /* Attempt to merge SEC_MERGE sections. */ bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); @@ -6274,6 +6812,9 @@ bfd_boolean bfd_compress_section_contents bfd_boolean bfd_get_full_section_contents (bfd *abfd, asection *section, bfd_byte **ptr); +void bfd_cache_section_contents + (asection *sec, void *contents); + bfd_boolean bfd_is_section_compressed (bfd *abfd, asection *section); diff --git a/contrib/gdb-7/bfd/bfd.c b/contrib/gdb-7/bfd/bfd.c index 7c14c7a00a..d77b90f931 100644 --- a/contrib/gdb-7/bfd/bfd.c +++ b/contrib/gdb-7/bfd/bfd.c @@ -797,6 +797,88 @@ bfd_get_error_handler (void) { return _bfd_error_handler; } + +/* +SUBSECTION + BFD assert handler + + If BFD finds an internal inconsistency, the bfd assert + handler is called with information on the BFD version, BFD + source file and line. If this happens, most programs linked + against BFD are expected to want to exit with an error, or mark + the current BFD operation as failed, so it is recommended to + override the default handler, which just calls + _bfd_error_handler and continues. + +CODE_FRAGMENT +. +.typedef void (*bfd_assert_handler_type) (const char *bfd_formatmsg, +. const char *bfd_version, +. const char *bfd_file, +. int bfd_line); +. +*/ + +/* Note the use of bfd_ prefix on the parameter names above: we want to + show which one is the message and which is the version by naming the + parameters, but avoid polluting the program-using-bfd namespace as + the typedef is visible in the exported headers that the program + includes. Below, it's just for consistency. */ + +static void +_bfd_default_assert_handler (const char *bfd_formatmsg, + const char *bfd_version, + const char *bfd_file, + int bfd_line) + +{ + (*_bfd_error_handler) (bfd_formatmsg, bfd_version, bfd_file, bfd_line); +} + +/* Similar to _bfd_error_handler, a program can decide to exit on an + internal BFD error. We use a non-variadic type to simplify passing + on parameters to other functions, e.g. _bfd_error_handler. */ + +bfd_assert_handler_type _bfd_assert_handler = _bfd_default_assert_handler; + +/* +FUNCTION + bfd_set_assert_handler + +SYNOPSIS + bfd_assert_handler_type bfd_set_assert_handler (bfd_assert_handler_type); + +DESCRIPTION + Set the BFD assert handler function. Returns the previous + function. +*/ + +bfd_assert_handler_type +bfd_set_assert_handler (bfd_assert_handler_type pnew) +{ + bfd_assert_handler_type pold; + + pold = _bfd_assert_handler; + _bfd_assert_handler = pnew; + return pold; +} + +/* +FUNCTION + bfd_get_assert_handler + +SYNOPSIS + bfd_assert_handler_type bfd_get_assert_handler (void); + +DESCRIPTION + Return the BFD assert handler function. +*/ + +bfd_assert_handler_type +bfd_get_assert_handler (void) +{ + return _bfd_assert_handler; +} /* SECTION @@ -942,8 +1024,8 @@ bfd_set_file_flags (bfd *abfd, flagword flags) void bfd_assert (const char *file, int line) { - (*_bfd_error_handler) (_("BFD %s assertion fail %s:%d"), - BFD_VERSION_STRING, file, line); + (*_bfd_assert_handler) (_("BFD %s assertion fail %s:%d"), + BFD_VERSION_STRING, file, line); } /* A more or less friendly abort message. In libbfd.h abort is @@ -1342,6 +1424,11 @@ DESCRIPTION . BFD_SEND (abfd, _bfd_find_nearest_line, \ . (abfd, sec, syms, off, file, func, line)) . +.#define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \ +. line, disc) \ +. BFD_SEND (abfd, _bfd_find_nearest_line_discriminator, \ +. (abfd, sec, syms, off, file, func, line, disc)) +. .#define bfd_find_line(abfd, syms, sym, file, line) \ . BFD_SEND (abfd, _bfd_find_line, \ . (abfd, syms, sym, file, line)) @@ -1374,8 +1461,8 @@ DESCRIPTION .#define bfd_gc_sections(abfd, link_info) \ . BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) . -.#define bfd_lookup_section_flags(link_info, flag_info) \ -. BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info)) +.#define bfd_lookup_section_flags(link_info, flag_info, section) \ +. BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info, section)) . .#define bfd_merge_sections(abfd, link_info) \ . BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) @@ -1493,7 +1580,7 @@ bfd_record_phdr (bfd *abfd, if (count > 0) memcpy (m->sections, secs, count * sizeof (asection *)); - for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next) + for (pm = &elf_seg_map (abfd); *pm != NULL; pm = &(*pm)->next) ; *pm = m; @@ -1599,128 +1686,6 @@ bfd_alt_mach_code (bfd *abfd, int alternative) return FALSE; } -/* -CODE_FRAGMENT - -.struct bfd_preserve -.{ -. void *marker; -. void *tdata; -. flagword flags; -. const struct bfd_arch_info *arch_info; -. struct bfd_section *sections; -. struct bfd_section *section_last; -. unsigned int section_count; -. struct bfd_hash_table section_htab; -.}; -. -*/ - -/* -FUNCTION - bfd_preserve_save - -SYNOPSIS - bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); - -DESCRIPTION - When testing an object for compatibility with a particular - target back-end, the back-end object_p function needs to set - up certain fields in the bfd on successfully recognizing the - object. This typically happens in a piecemeal fashion, with - failures possible at many points. On failure, the bfd is - supposed to be restored to its initial state, which is - virtually impossible. However, restoring a subset of the bfd - state works in practice. This function stores the subset and - reinitializes the bfd. - -*/ - -bfd_boolean -bfd_preserve_save (bfd *abfd, struct bfd_preserve *preserve) -{ - preserve->tdata = abfd->tdata.any; - preserve->arch_info = abfd->arch_info; - preserve->flags = abfd->flags; - preserve->sections = abfd->sections; - preserve->section_last = abfd->section_last; - preserve->section_count = abfd->section_count; - preserve->section_htab = abfd->section_htab; - - if (! bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc, - sizeof (struct section_hash_entry))) - return FALSE; - - abfd->tdata.any = NULL; - abfd->arch_info = &bfd_default_arch_struct; - abfd->flags &= BFD_FLAGS_SAVED; - abfd->sections = NULL; - abfd->section_last = NULL; - abfd->section_count = 0; - - return TRUE; -} - -/* -FUNCTION - bfd_preserve_restore - -SYNOPSIS - void bfd_preserve_restore (bfd *, struct bfd_preserve *); - -DESCRIPTION - This function restores bfd state saved by bfd_preserve_save. - If MARKER is non-NULL in struct bfd_preserve then that block - and all subsequently bfd_alloc'd memory is freed. - -*/ - -void -bfd_preserve_restore (bfd *abfd, struct bfd_preserve *preserve) -{ - bfd_hash_table_free (&abfd->section_htab); - - abfd->tdata.any = preserve->tdata; - abfd->arch_info = preserve->arch_info; - abfd->flags = preserve->flags; - abfd->section_htab = preserve->section_htab; - abfd->sections = preserve->sections; - abfd->section_last = preserve->section_last; - abfd->section_count = preserve->section_count; - - /* bfd_release frees all memory more recently bfd_alloc'd than - its arg, as well as its arg. */ - if (preserve->marker != NULL) - { - bfd_release (abfd, preserve->marker); - preserve->marker = NULL; - } -} - -/* -FUNCTION - bfd_preserve_finish - -SYNOPSIS - void bfd_preserve_finish (bfd *, struct bfd_preserve *); - -DESCRIPTION - This function should be called when the bfd state saved by - bfd_preserve_save is no longer needed. ie. when the back-end - object_p function returns with success. - -*/ - -void -bfd_preserve_finish (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_preserve *preserve) -{ - /* It would be nice to be able to free more memory here, eg. old - tdata, but that's not possible since these blocks are sitting - inside bfd_alloc'd memory. The section hash is on a separate - objalloc. */ - bfd_hash_table_free (&preserve->section_htab); -} - /* FUNCTION bfd_emul_get_maxpagesize diff --git a/contrib/gdb-7/bfd/bfdio.c b/contrib/gdb-7/bfd/bfdio.c index 841c781f4b..be05581aeb 100644 --- a/contrib/gdb-7/bfd/bfdio.c +++ b/contrib/gdb-7/bfd/bfdio.c @@ -87,7 +87,6 @@ FILE * real_fopen (const char *filename, const char *modes) { #ifdef VMS - char vms_modes[4]; char *vms_attr; /* On VMS, fopen allows file attributes as optionnal arguments. @@ -185,7 +184,8 @@ bfd_bread (void *ptr, bfd_size_type size, bfd *abfd) this element. */ if (abfd->arelt_data != NULL) { - size_t maxbytes = ((struct areltdata *) abfd->arelt_data)->parsed_size; + bfd_size_type maxbytes = arelt_size (abfd); + if (abfd->where + size > maxbytes) { if (abfd->where >= maxbytes) @@ -233,10 +233,14 @@ bfd_tell (bfd *abfd) if (abfd->iovec) { + bfd *parent_bfd = abfd; ptr = abfd->iovec->btell (abfd); - if (abfd->my_archive) - ptr -= abfd->origin; + while (parent_bfd->my_archive != NULL) + { + ptr -= parent_bfd->origin; + parent_bfd = parent_bfd->my_archive; + } } else ptr = 0; @@ -308,8 +312,16 @@ bfd_seek (bfd *abfd, file_ptr position, int direction) } file_position = position; - if (direction == SEEK_SET && abfd->my_archive != NULL) - file_position += abfd->origin; + if (direction == SEEK_SET) + { + bfd *parent_bfd = abfd; + + while (parent_bfd->my_archive != NULL) + { + file_position += parent_bfd->origin; + parent_bfd = parent_bfd->my_archive; + } + } if (abfd->iovec) result = abfd->iovec->bseek (abfd, file_position, direction); @@ -574,7 +586,7 @@ memory_bclose (struct bfd *abfd) free (bim); abfd->iostream = NULL; - return TRUE; + return 0; } static int diff --git a/contrib/gdb-7/bfd/cache.c b/contrib/gdb-7/bfd/cache.c index 5ddbbe470a..52268162c2 100644 --- a/contrib/gdb-7/bfd/cache.c +++ b/contrib/gdb-7/bfd/cache.c @@ -198,7 +198,7 @@ bfd_cache_lookup_worker (bfd *abfd, enum cache_flag flag) if ((abfd->flags & BFD_IN_MEMORY) != 0) abort (); - if (abfd->my_archive) + while (abfd->my_archive) abfd = abfd->my_archive; if (abfd->iostream != NULL) @@ -362,7 +362,7 @@ cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes) static int cache_bclose (struct bfd *abfd) { - return bfd_cache_close (abfd); + return bfd_cache_close (abfd) - 1; } static int @@ -437,7 +437,7 @@ cache_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED, { *map_addr = ret; *map_len = pg_len; - ret += offset & pagesize_m1; + ret = (char *) ret + (offset & pagesize_m1); } } #endif @@ -563,15 +563,15 @@ bfd_open_file (bfd *abfd) { case read_direction: case no_direction: - abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_RB); + abfd->iostream = real_fopen (abfd->filename, FOPEN_RB); break; case both_direction: case write_direction: if (abfd->opened_once) { - abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_RUB); + abfd->iostream = real_fopen (abfd->filename, FOPEN_RUB); if (abfd->iostream == NULL) - abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_WUB); + abfd->iostream = real_fopen (abfd->filename, FOPEN_WUB); } else { @@ -601,7 +601,7 @@ bfd_open_file (bfd *abfd) if (stat (abfd->filename, &s) == 0 && s.st_size != 0) unlink_if_ordinary (abfd->filename); #endif - abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_WUB); + abfd->iostream = real_fopen (abfd->filename, FOPEN_WUB); abfd->opened_once = TRUE; } break; diff --git a/contrib/gdb-7/bfd/coffgen.c b/contrib/gdb-7/bfd/coffgen.c index c0505c6c02..7d48ea9cf6 100644 --- a/contrib/gdb-7/bfd/coffgen.c +++ b/contrib/gdb-7/bfd/coffgen.c @@ -91,7 +91,7 @@ make_a_section_from_file (bfd *abfd, don't know the length of the string table. */ strings += strindex; name = (char *) bfd_alloc (abfd, - (bfd_size_type) strlen (strings) + 1); + (bfd_size_type) strlen (strings) + 1 + 1); if (name == NULL) return FALSE; strcpy (name, strings); @@ -102,7 +102,7 @@ make_a_section_from_file (bfd *abfd, { /* Assorted wastage to null-terminate the name, thanks AT&T! */ name = (char *) bfd_alloc (abfd, - (bfd_size_type) sizeof (hdr->s_name) + 1); + (bfd_size_type) sizeof (hdr->s_name) + 1 + 1); if (name == NULL) return FALSE; strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name)); @@ -146,6 +146,76 @@ make_a_section_from_file (bfd *abfd, if (hdr->s_scnptr != 0) return_section->flags |= SEC_HAS_CONTENTS; + /* Compress/decompress DWARF debug sections with names: .debug_* and + .zdebug_*, after the section flags is set. */ + if ((flags & SEC_DEBUGGING) + && ((name[1] == 'd' && name[6] == '_') + || (name[1] == 'z' && name[7] == '_'))) + { + enum { nothing, compress, decompress } action = nothing; + char *new_name = NULL; + + if (bfd_is_section_compressed (abfd, return_section)) + { + /* Compressed section. Check if we should decompress. */ + if ((abfd->flags & BFD_DECOMPRESS)) + action = decompress; + } + else if (!bfd_is_section_compressed (abfd, return_section)) + { + /* Normal section. Check if we should compress. */ + if ((abfd->flags & BFD_COMPRESS) && return_section->size != 0) + action = compress; + } + + switch (action) + { + case nothing: + break; + case compress: + if (!bfd_init_section_compress_status (abfd, return_section)) + { + (*_bfd_error_handler) + (_("%B: unable to initialize compress status for section %s"), + abfd, name); + return FALSE; + } + if (name[1] != 'z') + { + unsigned int len = strlen (name); + + new_name = bfd_alloc (abfd, len + 2); + if (new_name == NULL) + return FALSE; + new_name[0] = '.'; + new_name[1] = 'z'; + memcpy (new_name + 2, name + 1, len); + } + break; + case decompress: + if (!bfd_init_section_decompress_status (abfd, return_section)) + { + (*_bfd_error_handler) + (_("%B: unable to initialize decompress status for section %s"), + abfd, name); + return FALSE; + } + if (name[1] == 'z') + { + unsigned int len = strlen (name); + + new_name = bfd_alloc (abfd, len); + if (new_name == NULL) + return FALSE; + new_name[0] = '.'; + memcpy (new_name + 1, name + 2, len - 1); + } + break; + } + if (new_name != NULL) + bfd_rename_section (abfd, return_section, new_name); + } + return result; } @@ -577,7 +647,7 @@ fixup_symbol_value (bfd *abfd, struct internal_syment *syment) { /* Normalize the symbol flags. */ - if (coff_symbol_ptr->symbol.section + if (coff_symbol_ptr->symbol.section && bfd_is_com_section (coff_symbol_ptr->symbol.section)) { /* A common symbol is undefined with a value. */ @@ -1449,7 +1519,7 @@ coff_pointerize_aux (bfd *abfd, /* Otherwise patch up. */ #define N_TMASK coff_data (abfd)->local_n_tmask #define N_BTSHFT coff_data (abfd)->local_n_btshft - + if ((ISFCN (type) || ISTAG (n_sclass) || n_sclass == C_BLOCK || n_sclass == C_FCN) && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0) @@ -1872,7 +1942,7 @@ coff_bfd_make_debug_symbol (bfd *abfd, new_symbol->lineno = NULL; new_symbol->done_lineno = FALSE; new_symbol->symbol.the_bfd = abfd; - + return & new_symbol->symbol; } @@ -2153,7 +2223,7 @@ coff_find_nearest_line_with_names (bfd *abfd, if (_bfd_dwarf2_find_nearest_line (abfd, debug_sections, section, symbols, offset, filename_ptr, functionname_ptr, - line_ptr, 0, + line_ptr, NULL, 0, &coff_data(abfd)->dwarf2_find_line_info)) return TRUE; @@ -2348,6 +2418,24 @@ coff_find_nearest_line (bfd *abfd, line_ptr); } +bfd_boolean +coff_find_nearest_line_discriminator (bfd *abfd, + asection *section, + asymbol **symbols, + bfd_vma offset, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *line_ptr, + unsigned int *discriminator) +{ + *discriminator = 0; + return coff_find_nearest_line_with_names (abfd, dwarf_debug_sections, + section, symbols, offset, + filename_ptr, functionname_ptr, + line_ptr); +} + + bfd_boolean coff_find_inliner_info (bfd *abfd, const char **filename_ptr, diff --git a/contrib/gdb-7/bfd/compress.c b/contrib/gdb-7/bfd/compress.c index a82a8bc9e3..eb3bc536ff 100644 --- a/contrib/gdb-7/bfd/compress.c +++ b/contrib/gdb-7/bfd/compress.c @@ -1,5 +1,5 @@ /* Compressed section support (intended for debug sections). - Copyright 2008, 2010, 2011 + Copyright 2008, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "config.h" #include "sysdep.h" #include "bfd.h" #include "libbfd.h" @@ -47,7 +46,7 @@ decompress_contents (bfd_byte *compressed_buffer, strm.avail_out = uncompressed_size; rc = inflateInit (&strm); - while (strm.avail_in > 0) + while (strm.avail_in > 0 && strm.avail_out > 0) { if (rc != Z_OK) return FALSE; @@ -80,7 +79,7 @@ DESCRIPTION field was allocated using bfd_malloc() or equivalent. If zlib is not installed on this machine, the input is unmodified. - Return @code{TRUE} if the full section contents is compressed + Return @code{TRUE} if the full section contents is compressed successfully. */ @@ -149,7 +148,7 @@ SYNOPSIS DESCRIPTION Read all data from @var{section} in BFD @var{abfd}, decompress if needed, and store in @var{*ptr}. If @var{*ptr} is NULL, - return @var{*ptr} with memory malloc'd by this function. + return @var{*ptr} with memory malloc'd by this function. Return @code{TRUE} if the full section contents is retrieved successfully. @@ -162,11 +161,9 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) bfd_byte *p = *ptr; #ifdef HAVE_ZLIB_H bfd_boolean ret; - bfd_size_type compressed_size; - bfd_size_type uncompressed_size; - bfd_size_type rawsize; + bfd_size_type save_size; + bfd_size_type save_rawsize; bfd_byte *compressed_buffer; - bfd_byte *uncompressed_buffer; #endif if (abfd->direction != write_direction && sec->rawsize != 0) @@ -200,45 +197,44 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) return FALSE; #else /* Read in the full compressed section contents. */ - uncompressed_size = sec->size; - compressed_size = sec->compressed_size; - compressed_buffer = (bfd_byte *) bfd_malloc (compressed_size); + compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size); if (compressed_buffer == NULL) return FALSE; - rawsize = sec->rawsize; + save_rawsize = sec->rawsize; + save_size = sec->size; /* Clear rawsize, set size to compressed size and set compress_status to COMPRESS_SECTION_NONE. If the compressed size is bigger than the uncompressed size, bfd_get_section_contents will fail. */ sec->rawsize = 0; - sec->size = compressed_size; + sec->size = sec->compressed_size; sec->compress_status = COMPRESS_SECTION_NONE; ret = bfd_get_section_contents (abfd, sec, compressed_buffer, - 0, compressed_size); + 0, sec->compressed_size); /* Restore rawsize and size. */ - sec->rawsize = rawsize; - sec->size = uncompressed_size; + sec->rawsize = save_rawsize; + sec->size = save_size; sec->compress_status = DECOMPRESS_SECTION_SIZED; if (!ret) goto fail_compressed; - uncompressed_buffer = (bfd_byte *) bfd_malloc (uncompressed_size); - if (uncompressed_buffer == NULL) + if (p == NULL) + p = (bfd_byte *) bfd_malloc (sz); + if (p == NULL) goto fail_compressed; - if (!decompress_contents (compressed_buffer, compressed_size, - uncompressed_buffer, uncompressed_size)) + if (!decompress_contents (compressed_buffer, sec->compressed_size, p, sz)) { bfd_set_error (bfd_error_bad_value); - free (uncompressed_buffer); + if (p != *ptr) + free (p); fail_compressed: free (compressed_buffer); return FALSE; } free (compressed_buffer); - sec->contents = uncompressed_buffer; - sec->compress_status = COMPRESS_SECTION_DONE; - /* Fall thru */ + *ptr = p; + return TRUE; #endif case COMPRESS_SECTION_DONE: @@ -257,6 +253,29 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) } } +/* +FUNCTION + bfd_cache_section_contents + +SYNOPSIS + void bfd_cache_section_contents + (asection *sec, void *contents); + +DESCRIPTION + Stash @var(contents) so any following reads of @var(sec) do + not need to decompress again. +*/ + +void +bfd_cache_section_contents (asection *sec, void *contents) +{ + if (sec->compress_status == DECOMPRESS_SECTION_SIZED) + sec->compress_status = COMPRESS_SECTION_DONE; + sec->contents = contents; + sec->flags |= SEC_IN_MEMORY; +} + + /* FUNCTION bfd_is_section_compressed @@ -273,11 +292,20 @@ bfd_boolean bfd_is_section_compressed (bfd *abfd, sec_ptr sec) { bfd_byte compressed_buffer [12]; + unsigned int saved = sec->compress_status; + bfd_boolean compressed; + + /* Don't decompress the section. */ + sec->compress_status = COMPRESS_SECTION_NONE; /* Read the zlib header. In this case, it should be "ZLIB" followed by the uncompressed section size, 8 bytes in big-endian order. */ - return (bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12) - && CONST_STRNEQ ((char*) compressed_buffer, "ZLIB")); + compressed = (bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12) + && CONST_STRNEQ ((char*) compressed_buffer, "ZLIB")); + + /* Restore compress_status. */ + sec->compress_status = saved; + return compressed; } /* diff --git a/contrib/gdb-7/bfd/config.bfd b/contrib/gdb-7/bfd/config.bfd index 5337ce55b8..10820e2cba 100644 --- a/contrib/gdb-7/bfd/config.bfd +++ b/contrib/gdb-7/bfd/config.bfd @@ -1,4 +1,21 @@ # config.bfd +# +# Copyright 2012, 2013 Free Software Foundation +# +# This file 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; see the file COPYING3. If not see +# . +# # Convert a canonical host type into a BFD host type. # Set shell variable targ to canonical target name, and run # using ``. config.bfd''. @@ -69,6 +86,7 @@ esac targ_cpu=`echo $targ | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` case "${targ_cpu}" in +aarch64*) targ_archs="bfd_aarch64_arch bfd_arm_arch";; alpha*) targ_archs=bfd_alpha_arch ;; am34*|am33_2.0*) targ_archs=bfd_mn10300_arch ;; arm*) targ_archs=bfd_arm_arch ;; @@ -85,12 +103,13 @@ hppa*) targ_archs=bfd_hppa_arch ;; i[3-7]86) targ_archs=bfd_i386_arch ;; i370) targ_archs=bfd_i370_arch ;; lm32) targ_archs=bfd_lm32_arch ;; -m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch" ;; -m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch" ;; +m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; +m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; m68*) targ_archs=bfd_m68k_arch ;; m88*) targ_archs=bfd_m88k_arch ;; microblaze*) targ_archs=bfd_microblaze_arch ;; mips*) targ_archs=bfd_mips_arch ;; +nios2*) targ_archs=bfd_nios2_arch ;; or32*) targ_archs=bfd_or32_arch ;; pdp11*) targ_archs=bfd_pdp11_arch ;; pj*) targ_archs="bfd_pj_arch bfd_i386_arch";; @@ -102,9 +121,10 @@ sparc*) targ_archs=bfd_sparc_arch ;; spu*) targ_archs=bfd_spu_arch ;; tilegx*) targ_archs=bfd_tilegx_arch ;; tilepro*) targ_archs=bfd_tilepro_arch ;; -v850*) targ_archs=bfd_v850_arch ;; +v850*) targ_archs="bfd_v850_arch bfd_v850_rh850_arch" ;; x86_64*) targ_archs=bfd_i386_arch ;; xtensa*) targ_archs=bfd_xtensa_arch ;; +xgate) targ_archs=bfd_xgate_arch ;; z80|r800) targ_archs=bfd_z80_arch ;; z8k*) targ_archs=bfd_z8k_arch ;; *) targ_archs=bfd_${targ_cpu}_arch ;; @@ -142,6 +162,26 @@ case "${targ}" in # START OF targmatch.h #ifdef BFD64 + aarch64-*-elf) + targ_defvec=bfd_elf64_littleaarch64_vec + targ_selvecs="bfd_elf64_bigaarch64_vec bfd_elf32_littlearm_vec bfd_elf32_bigarm_vec" + want64=true + ;; + aarch64_be-*-elf) + targ_defvec=bfd_elf64_bigaarch64_vec + targ_selvecs="bfd_elf64_littleaarch64_vec bfd_elf32_bigarm_vec bfd_elf32_littlearm_vec" + want64=true + ;; + aarch64-*-linux*) + targ_defvec=bfd_elf64_littleaarch64_vec + targ_selvecs="bfd_elf64_bigaarch64_vec bfd_elf32_littlearm_vec bfd_elf32_bigarm_vec" + want64=true + ;; + aarch64_be-*-linux*) + targ_defvec=bfd_elf64_bigaarch64_vec + targ_selvecs="bfd_elf64_littleaarch64_vec bfd_elf32_bigarm_vec bfd_elf32_littlearm_vec" + want64=true + ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) targ_defvec=bfd_elf64_alpha_freebsd_vec targ_selvecs="bfd_elf64_alpha_vec ecoffalpha_little_vec" @@ -216,6 +256,18 @@ case "${targ}" in targ_selvecs=bfd_elf32_bigarc_vec ;; + arm-*-nacl*) + targ_defvec=bfd_elf32_littlearm_nacl_vec + targ_selvecs="bfd_elf32_bigarm_nacl_vec bfd_elf32_i386_nacl_vec" + targ64_selvecs="bfd_elf32_x86_64_nacl_vec bfd_elf64_x86_64_nacl_vec" + targ_archs="$targ_archs bfd_i386_arch" + ;; + armeb-*-nacl*) + targ_defvec=bfd_elf32_bigarm_nacl_vec + targ_selvecs="bfd_elf32_littlearm_nacl_vec bfd_elf32_i386_nacl_vec" + targ64_selvecs="bfd_elf32_x86_64_nacl_vec bfd_elf64_x86_64_nacl_vec" + targ_archs="$targ_archs bfd_i386_arch" + ;; armeb-*-netbsdelf*) targ_defvec=bfd_elf32_bigarm_vec targ_selvecs="bfd_elf32_littlearm_vec armnetbsd_vec" @@ -327,7 +379,7 @@ case "${targ}" in targ_underscore=yes ;; - cr16-*-elf*) + cr16-*-elf* | cr16*-*-uclinux*) targ_defvec=bfd_elf32_cr16_vec targ_underscore=yes ;; @@ -384,8 +436,9 @@ case "${targ}" in targ_selvecs=bfd_elf32_frv_vec ;; - moxie-*-elf | moxie-*-rtems | moxie-*-uclinux) - targ_defvec=bfd_elf32_moxie_vec + moxie-*-elf | moxie-*-rtems* | moxie-*-uclinux) + targ_defvec=bfd_elf32_bigmoxie_vec + targ_selvecs=bfd_elf32_littlemoxie_vec ;; h8300*-*-rtemscoff*) @@ -507,9 +560,10 @@ case "${targ}" in i[3-7]86-*-darwin* | i[3-7]86-*-macos10* | i[3-7]86-*-rhapsody*) targ_defvec=mach_o_i386_vec targ_selvecs="mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" + targ64_selvecs=mach_o_x86_64_vec targ_archs="$targ_archs bfd_powerpc_arch bfd_rs6000_arch" ;; - i[3-7]86-sequent-bsd*) + i[3-7]86-sequent-bsd*) targ_defvec=i386dynix_vec targ_underscore=yes ;; @@ -568,11 +622,13 @@ case "${targ}" in i[3-7]86-*-linux-*) targ_defvec=bfd_elf32_i386_vec targ_selvecs="i386linux_vec i386pei_vec" - targ64_selvecs="bfd_elf64_x86_64_vec bfd_elf32_x86_64_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" + targ64_selvecs="bfd_elf64_x86_64_vec bfd_elf32_x86_64_vec x86_64pei_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" ;; i[3-7]86-*-nacl*) targ_defvec=bfd_elf32_i386_nacl_vec - targ_selvecs="bfd_elf32_i386_vec" + targ_selvecs="bfd_elf32_bigarm_nacl_vec bfd_elf32_littlearm_nacl_vec" + targ64_selvecs="bfd_elf64_x86_64_nacl_vec bfd_elf32_x86_64_nacl_vec" + targ_archs="$targ_archs bfd_arm_arch" ;; #ifdef BFD64 x86_64-*-darwin*) @@ -611,12 +667,22 @@ case "${targ}" in targ_selvecs="bfd_elf32_i386_vec bfd_elf32_x86_64_vec i386linux_vec i386pei_vec x86_64pei_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec" want64=true ;; - x86_64-*-mingw* | x86_64-*-pe | x86_64-*-pep) + x86_64-*-nacl*) + targ_defvec=bfd_elf32_x86_64_nacl_vec + targ_selvecs="bfd_elf32_i386_nacl_vec bfd_elf64_x86_64_nacl_vec bfd_elf32_bigarm_nacl_vec bfd_elf32_littlearm_nacl_vec" + targ_archs="$targ_archs bfd_arm_arch" + want64=true + ;; + x86_64-*-mingw* | x86_64-*-pe | x86_64-*-pep | x86_64-*-cygwin) targ_defvec=x86_64pe_vec targ_selvecs="x86_64pe_vec x86_64pei_vec bfd_elf64_x86_64_vec bfd_elf64_l1om_vec bfd_elf64_k1om_vec i386pe_vec i386pei_vec bfd_elf32_i386_vec" want64=true targ_underscore=no ;; + x86_64-*-rdos*) + targ_defvec=bfd_elf64_x86_64_vec + want64=true + ;; #endif i[3-7]86-*-lynxos*) targ_defvec=bfd_elf32_i386_vec @@ -872,8 +938,19 @@ case "${targ}" in targ_selvecs=bfd_elf32_mep_little_vec ;; + metag-*-*) + targ_defvec=bfd_elf32_metag_vec + targ_underscore=yes + ;; + + microblazeel*-*) + targ_defvec=bfd_elf32_microblazeel_vec + targ_selvecs=bfd_elf32_microblaze_vec + ;; + microblaze*-*) targ_defvec=bfd_elf32_microblaze_vec + targ_selvecs=bfd_elf32_microblazeel_vec ;; mips*-big-*) @@ -902,7 +979,16 @@ case "${targ}" in targ_selvecs="bfd_elf32_nlittlemips_vec bfd_elf32_bigmips_vec bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" want64=true ;; + mips64*-ps2-elf*) + targ_defvec=bfd_elf32_nlittlemips_vec + targ_selvecs="bfd_elf32_nlittlemips_vec bfd_elf32_nbigmips_vec bfd_elf32_bigmips_vec bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + want64=true + ;; #endif + mips*-ps2-elf*) + targ_defvec=bfd_elf32_littlemips_vec + targ_selvecs="bfd_elf32_bigmips_vec bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + ;; mips*-*-irix5*) targ_defvec=bfd_elf32_bigmips_vec targ_selvecs="bfd_elf32_littlemips_vec ecoff_big_vec ecoff_little_vec" @@ -940,7 +1026,7 @@ case "${targ}" in targ_selvecs="bfd_elf32_tradbigmips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" want64=true ;; - mips*-sde-elf*) + mips*-sde-elf* | mips*-mti-elf*) targ_defvec=bfd_elf32_tradbigmips_vec targ_selvecs="bfd_elf32_tradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" want64=true @@ -983,7 +1069,6 @@ case "${targ}" in targ_selvecs="bfd_elf32_ntradlittlemips_vec bfd_elf32_tradbigmips_vec bfd_elf32_tradlittlemips_vec bfd_elf64_tradbigmips_vec bfd_elf64_tradlittlemips_vec" want64=true ;; -#endif mips*el-*-linux*) targ_defvec=bfd_elf32_tradlittlemips_vec targ_selvecs="bfd_elf32_tradbigmips_vec ecoff_little_vec ecoff_big_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradlittlemips_vec bfd_elf32_ntradbigmips_vec bfd_elf64_tradbigmips_vec" @@ -994,7 +1079,6 @@ case "${targ}" in targ_selvecs="bfd_elf32_tradlittlemips_vec ecoff_big_vec ecoff_little_vec bfd_elf32_ntradbigmips_vec bfd_elf64_tradbigmips_vec bfd_elf32_ntradlittlemips_vec bfd_elf64_tradlittlemips_vec" want64=true ;; -#ifdef BFD64 mips64*el-*-freebsd* | mips64*el-*-kfreebsd*-gnu) # FreeBSD vectors targ_defvec=bfd_elf32_ntradlittlemips_freebsd_vec @@ -1061,6 +1145,21 @@ case "${targ}" in targ_underscore=yes ;; + nios2eb-*-*) + targ_defvec=bfd_elf32_bignios2_vec + targ_selvecs=bfd_elf32_littlenios2_vec + ;; + + nios2el-*-*) + targ_defvec=bfd_elf32_littlenios2_vec + targ_selvecs=bfd_elf32_bignios2_vec + ;; + + nios2-*-*) + targ_defvec=bfd_elf32_littlenios2_vec + targ_selvecs=bfd_elf32_bignios2_vec + ;; + openrisc-*-elf) targ_defvec=bfd_elf32_openrisc_vec ;; @@ -1506,8 +1605,12 @@ case "${targ}" in #ifdef BFD64 tilegx-*-*) - targ_defvec=bfd_elf64_tilegx_vec - targ_selvecs=bfd_elf32_tilegx_vec + targ_defvec=bfd_elf64_tilegx_le_vec + targ_selvecs="bfd_elf64_tilegx_be_vec bfd_elf32_tilegx_be_vec bfd_elf32_tilegx_le_vec" + ;; + tilegxbe-*-*) + targ_defvec=bfd_elf64_tilegx_be_vec + targ_selvecs="bfd_elf64_tilegx_le_vec bfd_elf32_tilegx_be_vec bfd_elf32_tilegx_le_vec" ;; #endif @@ -1517,6 +1620,7 @@ case "${targ}" in v850*-*-*) targ_defvec=bfd_elf32_v850_vec + targ_selvecs="bfd_elf32_v850_rh850_vec" ;; vax-*-netbsdelf*) @@ -1551,7 +1655,12 @@ case "${targ}" in w65-*-*) targ_defvec=w65_vec ;; - + + xgate-*-*) + targ_defvec=bfd_elf32_xgate_vec + targ_selvecs="bfd_elf32_xgate_vec" + ;; + xstormy16-*-elf) targ_defvec=bfd_elf32_xstormy16_vec ;; diff --git a/contrib/gdb-7/bfd/corefile.c b/contrib/gdb-7/bfd/corefile.c index bba0d1ca4f..8d6293849f 100644 --- a/contrib/gdb-7/bfd/corefile.c +++ b/contrib/gdb-7/bfd/corefile.c @@ -169,7 +169,7 @@ generic_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) of the const char * returned by bfd_core_file_failing_command to a non-const char *. In this case, the assignement does not lead to breaking the const, as we're only reading the string. */ - + core = (char *) bfd_core_file_failing_command (core_bfd); if (core == NULL) return TRUE; @@ -185,7 +185,7 @@ generic_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) last_slash = strrchr (exec, '/'); if (last_slash != NULL) exec = last_slash + 1; - + return filename_cmp (exec, core) == 0; } diff --git a/contrib/gdb-7/bfd/cpu-i386.c b/contrib/gdb-7/bfd/cpu-i386.c index f98c0e5052..6174612ebb 100644 --- a/contrib/gdb-7/bfd/cpu-i386.c +++ b/contrib/gdb-7/bfd/cpu-i386.c @@ -23,6 +23,10 @@ #include "sysdep.h" #include "bfd.h" #include "libbfd.h" +#include "libiberty.h" + +extern void * bfd_arch_i386_short_nop_fill (bfd_size_type, bfd_boolean, + bfd_boolean); static const bfd_arch_info_type * bfd_i386_compatible (const bfd_arch_info_type *a, @@ -38,6 +42,83 @@ bfd_i386_compatible (const bfd_arch_info_type *a, return compat; } +/* Fill the buffer with zero or nop instruction if CODE is TRUE. Use + multi byte nop instructions if LONG_NOP is TRUE. */ + +static void * +bfd_arch_i386_fill (bfd_size_type count, bfd_boolean code, + bfd_boolean long_nop) +{ + /* nop */ + static const char nop_1[] = { 0x90 }; + /* xchg %ax,%ax */ + static const char nop_2[] = { 0x66, 0x90 }; + /* nopl (%[re]ax) */ + static const char nop_3[] = { 0x0f, 0x1f, 0x00 }; + /* nopl 0(%[re]ax) */ + static const char nop_4[] = { 0x0f, 0x1f, 0x40, 0x00 }; + /* nopl 0(%[re]ax,%[re]ax,1) */ + static const char nop_5[] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; + /* nopw 0(%[re]ax,%[re]ax,1) */ + static const char nop_6[] = { 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 }; + /* nopl 0L(%[re]ax) */ + static const char nop_7[] = { 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00 }; + /* nopl 0L(%[re]ax,%[re]ax,1) */ + static const char nop_8[] = + { 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; + /* nopw 0L(%[re]ax,%[re]ax,1) */ + static const char nop_9[] = + { 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /* nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char nop_10[] = + { 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const char *const nops[] = + { nop_1, nop_2, nop_3, nop_4, nop_5, + nop_6, nop_7, nop_8, nop_9, nop_10 }; + bfd_size_type nop_size = long_nop ? ARRAY_SIZE (nops) : 2; + + void *fill = bfd_malloc (count); + if (fill == NULL) + return fill; + + if (code) + { + bfd_byte *p = fill; + while (count >= nop_size) + { + memcpy (p, nops[nop_size - 1], nop_size); + p += nop_size; + count -= nop_size; + } + if (count != 0) + memcpy (p, nops[count - 1], count); + } + else + memset (fill, 0, count); + + return fill; +} + +/* Fill the buffer with zero or short nop instruction if CODE is TRUE. */ + +void * +bfd_arch_i386_short_nop_fill (bfd_size_type count, + bfd_boolean is_bigendian ATTRIBUTE_UNUSED, + bfd_boolean code) +{ + return bfd_arch_i386_fill (count, code, FALSE); +} + +/* Fill the buffer with zero or long nop instruction if CODE is TRUE. */ + +static void * +bfd_arch_i386_long_nop_fill (bfd_size_type count, + bfd_boolean is_bigendian ATTRIBUTE_UNUSED, + bfd_boolean code) +{ + return bfd_arch_i386_fill (count, code, TRUE); +} + static const bfd_arch_info_type bfd_x64_32_arch_intel_syntax = { 64, /* 64 bits in a word */ @@ -51,6 +132,7 @@ static const bfd_arch_info_type bfd_x64_32_arch_intel_syntax = FALSE, bfd_i386_compatible, bfd_default_scan, + bfd_arch_i386_long_nop_fill, 0 }; @@ -67,6 +149,7 @@ static const bfd_arch_info_type bfd_x86_64_arch_intel_syntax = FALSE, bfd_i386_compatible, bfd_default_scan, + bfd_arch_i386_long_nop_fill, &bfd_x64_32_arch_intel_syntax, }; @@ -83,6 +166,7 @@ static const bfd_arch_info_type bfd_i386_arch_intel_syntax = TRUE, bfd_i386_compatible, bfd_default_scan, + bfd_arch_i386_short_nop_fill, &bfd_x86_64_arch_intel_syntax }; @@ -99,6 +183,7 @@ static const bfd_arch_info_type i8086_arch = FALSE, bfd_i386_compatible, bfd_default_scan, + bfd_arch_i386_short_nop_fill, &bfd_i386_arch_intel_syntax }; @@ -115,6 +200,7 @@ static const bfd_arch_info_type bfd_x64_32_arch = FALSE, bfd_i386_compatible, bfd_default_scan, + bfd_arch_i386_long_nop_fill, &i8086_arch }; @@ -131,6 +217,7 @@ static const bfd_arch_info_type bfd_x86_64_arch = FALSE, bfd_i386_compatible, bfd_default_scan, + bfd_arch_i386_long_nop_fill, &bfd_x64_32_arch }; @@ -147,5 +234,6 @@ const bfd_arch_info_type bfd_i386_arch = TRUE, bfd_i386_compatible, bfd_default_scan, + bfd_arch_i386_short_nop_fill, &bfd_x86_64_arch }; diff --git a/contrib/gdb-7/bfd/cpu-l1om.c b/contrib/gdb-7/bfd/cpu-l1om.c index c1057c4e9b..46ac3a00c8 100644 --- a/contrib/gdb-7/bfd/cpu-l1om.c +++ b/contrib/gdb-7/bfd/cpu-l1om.c @@ -23,6 +23,9 @@ #include "bfd.h" #include "libbfd.h" +extern void * bfd_arch_i386_short_nop_fill (bfd_size_type, bfd_boolean, + bfd_boolean); + static const bfd_arch_info_type bfd_l1om_arch_intel_syntax = { 64, /* 64 bits in a word */ @@ -36,6 +39,7 @@ static const bfd_arch_info_type bfd_l1om_arch_intel_syntax = TRUE, bfd_default_compatible, bfd_default_scan, + bfd_arch_i386_short_nop_fill, 0 }; @@ -52,5 +56,6 @@ const bfd_arch_info_type bfd_l1om_arch = TRUE, bfd_default_compatible, bfd_default_scan, + bfd_arch_i386_short_nop_fill, &bfd_l1om_arch_intel_syntax }; diff --git a/contrib/gdb-7/bfd/dwarf2.c b/contrib/gdb-7/bfd/dwarf2.c index 577f278322..7a1a4aea0d 100644 --- a/contrib/gdb-7/bfd/dwarf2.c +++ b/contrib/gdb-7/bfd/dwarf2.c @@ -173,6 +173,9 @@ struct dwarf2_debug #define STASH_INFO_HASH_OFF 0 #define STASH_INFO_HASH_ON 1 #define STASH_INFO_HASH_DISABLED 2 + + /* True if we opened bfd_ptr. */ + bfd_boolean close_on_cleanup; }; struct arange @@ -405,8 +408,8 @@ create_info_hash_table (bfd *abfd) { struct info_hash_table *hash_table; - hash_table = (struct info_hash_table *) - bfd_alloc (abfd, sizeof (struct info_hash_table)); + hash_table = ((struct info_hash_table *) + bfd_alloc (abfd, sizeof (struct info_hash_table))); if (!hash_table) return hash_table; @@ -503,7 +506,7 @@ read_section (bfd * abfd, if (syms) { *section_buffer - = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms); + = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms); if (! *section_buffer) return FALSE; } @@ -522,7 +525,8 @@ read_section (bfd * abfd, that the client wants. Validate it here to avoid trouble later. */ if (offset != 0 && offset >= *section_size) { - (*_bfd_error_handler) (_("Dwarf Error: Offset (%lu) greater than or equal to %s size (%lu)."), + (*_bfd_error_handler) (_("Dwarf Error: Offset (%lu)" + " greater than or equal to %s size (%lu)."), (long) offset, section_name, *section_size); bfd_set_error (bfd_error_bad_value); return FALSE; @@ -979,6 +983,7 @@ struct line_info char *filename; unsigned int line; unsigned int column; + unsigned int discriminator; unsigned char op_index; unsigned char end_sequence; /* End of (sequential) code sequence. */ }; @@ -1014,20 +1019,27 @@ struct line_info_table /* Remember some information about each function. If the function is inlined (DW_TAG_inlined_subroutine) it may have two additional attributes, DW_AT_call_file and DW_AT_call_line, which specify the - source code location where this function was inlined. */ + source code location where this function was inlined. */ struct funcinfo { - struct funcinfo *prev_func; /* Pointer to previous function in list of all functions */ - struct funcinfo *caller_func; /* Pointer to function one scope higher */ - char *caller_file; /* Source location file name where caller_func inlines this func */ - int caller_line; /* Source location line number where caller_func inlines this func */ - char *file; /* Source location file name */ - int line; /* Source location line number */ + /* Pointer to previous function in list of all functions. */ + struct funcinfo *prev_func; + /* Pointer to function one scope higher. */ + struct funcinfo *caller_func; + /* Source location file name where caller_func inlines this func. */ + char *caller_file; + /* Source location line number where caller_func inlines this func. */ + int caller_line; + /* Source location file name. */ + char *file; + /* Source location line number. */ + int line; int tag; char *name; struct arange arange; - asection *sec; /* Where the symbol is defined */ + /* Where the symbol is defined. */ + asection *sec; }; struct varinfo @@ -1072,6 +1084,7 @@ add_line_info (struct line_info_table *table, char *filename, unsigned int line, unsigned int column, + unsigned int discriminator, int end_sequence) { bfd_size_type amt = sizeof (struct line_info); @@ -1087,6 +1100,7 @@ add_line_info (struct line_info_table *table, info->op_index = op_index; info->line = line; info->column = column; + info->discriminator = discriminator; info->end_sequence = end_sequence; if (filename && filename[0]) @@ -1248,12 +1262,16 @@ concat_filename (struct line_info_table *table, unsigned int file) } static bfd_boolean -arange_add (bfd *abfd, struct arange *first_arange, +arange_add (const struct comp_unit *unit, struct arange *first_arange, bfd_vma low_pc, bfd_vma high_pc) { struct arange *arange; - /* If the first arange is empty, use it. */ + /* Ignore empty ranges. */ + if (low_pc == high_pc) + return TRUE; + + /* If the first arange is empty, use it. */ if (first_arange->high == 0) { first_arange->low = low_pc; @@ -1281,7 +1299,7 @@ arange_add (bfd *abfd, struct arange *first_arange, /* Need to allocate a new arange and insert it into the arange list. Order isn't significant, so just insert after the first arange. */ - arange = (struct arange *) bfd_zalloc (abfd, sizeof (*arange)); + arange = (struct arange *) bfd_alloc (unit->abfd, sizeof (*arange)); if (arange == NULL) return FALSE; arange->low = low_pc; @@ -1401,6 +1419,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) unsigned int i, bytes_read, offset_size; char *cur_file, *cur_dir; unsigned char op_code, extended_op, adj_opcode; + unsigned int exop_len; bfd_size_type amt; if (! read_section (abfd, &stash->debug_sections[debug_line], @@ -1560,6 +1579,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) char * filename = table->num_files ? concat_filename (table, 1) : NULL; unsigned int line = 1; unsigned int column = 0; + unsigned int discriminator = 0; int is_stmt = lh.default_is_stmt; int end_sequence = 0; /* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some @@ -1581,21 +1601,22 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) /* Special operand. */ adj_opcode = op_code - lh.opcode_base; if (lh.maximum_ops_per_insn == 1) - address += (adj_opcode / lh.line_range) - * lh.minimum_instruction_length; + address += (adj_opcode / lh.line_range + * lh.minimum_instruction_length); else { - address += ((op_index + (adj_opcode / lh.line_range)) - / lh.maximum_ops_per_insn) - * lh.minimum_instruction_length; - op_index = (op_index + (adj_opcode / lh.line_range)) - % lh.maximum_ops_per_insn; + address += ((op_index + adj_opcode / lh.line_range) + / lh.maximum_ops_per_insn + * lh.minimum_instruction_length); + op_index = ((op_index + adj_opcode / lh.line_range) + % lh.maximum_ops_per_insn); } line += lh.line_base + (adj_opcode % lh.line_range); /* Append row to matrix using current values. */ if (!add_line_info (table, address, op_index, filename, - line, column, 0)) + line, column, discriminator, 0)) goto line_fail; + discriminator = 0; if (address < low_pc) low_pc = address; if (address > high_pc) @@ -1604,8 +1625,8 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) else switch (op_code) { case DW_LNS_extended_op: - /* Ignore length. */ - line_ptr += 1; + exop_len = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; extended_op = read_1_byte (abfd, line_ptr); line_ptr += 1; @@ -1613,14 +1634,15 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) { case DW_LNE_end_sequence: end_sequence = 1; - if (!add_line_info (table, address, op_index, filename, - line, column, end_sequence)) + if (!add_line_info (table, address, op_index, filename, line, + column, discriminator, end_sequence)) goto line_fail; + discriminator = 0; if (address < low_pc) low_pc = address; if (address > high_pc) high_pc = address; - if (!arange_add (unit->abfd, &unit->arange, low_pc, high_pc)) + if (!arange_add (unit, &unit->arange, low_pc, high_pc)) goto line_fail; break; case DW_LNE_set_address: @@ -1655,11 +1677,16 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) table->num_files++; break; case DW_LNE_set_discriminator: - (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + discriminator = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; break; + case DW_LNE_HP_source_file_correlation: + line_ptr += exop_len - 1; + break; default: - (*_bfd_error_handler) (_("Dwarf Error: mangled line number section.")); + (*_bfd_error_handler) + (_("Dwarf Error: mangled line number section.")); bfd_set_error (bfd_error_bad_value); line_fail: if (filename != NULL) @@ -1669,8 +1696,9 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) break; case DW_LNS_copy: if (!add_line_info (table, address, op_index, - filename, line, column, 0)) + filename, line, column, discriminator, 0)) goto line_fail; + discriminator = 0; if (address < low_pc) low_pc = address; if (address > high_pc) @@ -1678,15 +1706,15 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) break; case DW_LNS_advance_pc: if (lh.maximum_ops_per_insn == 1) - address += lh.minimum_instruction_length - * read_unsigned_leb128 (abfd, line_ptr, - &bytes_read); + address += (lh.minimum_instruction_length + * read_unsigned_leb128 (abfd, line_ptr, + &bytes_read)); else { bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - address = ((op_index + adjust) / lh.maximum_ops_per_insn) - * lh.minimum_instruction_length; + address = ((op_index + adjust) / lh.maximum_ops_per_insn + * lh.minimum_instruction_length); op_index = (op_index + adjust) % lh.maximum_ops_per_insn; } line_ptr += bytes_read; @@ -1719,13 +1747,14 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) break; case DW_LNS_const_add_pc: if (lh.maximum_ops_per_insn == 1) - address += lh.minimum_instruction_length - * ((255 - lh.opcode_base) / lh.line_range); + address += (lh.minimum_instruction_length + * ((255 - lh.opcode_base) / lh.line_range)); else { bfd_vma adjust = ((255 - lh.opcode_base) / lh.line_range); - address += lh.minimum_instruction_length - * ((op_index + adjust) / lh.maximum_ops_per_insn); + address += (lh.minimum_instruction_length + * ((op_index + adjust) + / lh.maximum_ops_per_insn)); op_index = (op_index + adjust) % lh.maximum_ops_per_insn; } break; @@ -1770,7 +1799,8 @@ static bfd_boolean lookup_address_in_line_info_table (struct line_info_table *table, bfd_vma addr, const char **filename_ptr, - unsigned int *linenumber_ptr) + unsigned int *linenumber_ptr, + unsigned int *discriminator_ptr) { struct line_sequence *seq = NULL; struct line_info *each_line; @@ -1805,6 +1835,8 @@ lookup_address_in_line_info_table (struct line_info_table *table, { *filename_ptr = each_line->filename; *linenumber_ptr = each_line->line; + if (discriminator_ptr) + *discriminator_ptr = each_line->discriminator; return TRUE; } } @@ -1851,8 +1883,9 @@ lookup_address_in_function_table (struct comp_unit *unit, { if (addr >= arange->low && addr < arange->high) { - if (!best_fit || - ((arange->high - arange->low) < (best_fit->arange.high - best_fit->arange.low))) + if (!best_fit + || (arange->high - arange->low + < best_fit->arange.high - best_fit->arange.low)) best_fit = each_func; } } @@ -1900,8 +1933,8 @@ lookup_symbol_in_function_table (struct comp_unit *unit, && each_func->name && strcmp (name, each_func->name) == 0 && (!best_fit - || ((arange->high - arange->low) - < (best_fit->arange.high - best_fit->arange.low)))) + || (arange->high - arange->low + < best_fit->arange.high - best_fit->arange.low))) best_fit = each_func; } } @@ -1976,7 +2009,7 @@ find_abstract_instance_name (struct comp_unit *unit, info_ptr = unit->sec_info_ptr + die_ref; } - else + else info_ptr = unit->info_ptr_unit + die_ref; abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; @@ -1986,8 +2019,8 @@ find_abstract_instance_name (struct comp_unit *unit, abbrev = lookup_abbrev (abbrev_number, unit->abbrevs); if (! abbrev) { - (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."), - abbrev_number); + (*_bfd_error_handler) + (_("Dwarf Error: Could not find abbrev number %u."), abbrev_number); bfd_set_error (bfd_error_bad_value); } else @@ -2052,7 +2085,7 @@ read_rangelist (struct comp_unit *unit, struct arange *arange, base_address = high_pc; else { - if (!arange_add (unit->abfd, arange, + if (!arange_add (unit, arange, base_address + low_pc, base_address + high_pc)) return FALSE; } @@ -2078,7 +2111,7 @@ scan_unit_for_symbols (struct comp_unit *unit) can use to set the caller_func field. */ nested_funcs_size = 32; nested_funcs = (struct funcinfo **) - bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *)); + bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *)); if (nested_funcs == NULL) return FALSE; nested_funcs[nesting_level] = 0; @@ -2092,6 +2125,7 @@ scan_unit_for_symbols (struct comp_unit *unit) struct varinfo *var; bfd_vma low_pc = 0; bfd_vma high_pc = 0; + bfd_boolean high_pc_relative = FALSE; abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; @@ -2197,6 +2231,7 @@ scan_unit_for_symbols (struct comp_unit *unit) case DW_AT_high_pc: high_pc = attr.u.val; + high_pc_relative = attr.form != DW_FORM_addr; break; case DW_AT_ranges: @@ -2275,9 +2310,12 @@ scan_unit_for_symbols (struct comp_unit *unit) } } + if (high_pc_relative) + high_pc += low_pc; + if (func && high_pc != 0) { - if (!arange_add (unit->abfd, &func->arange, low_pc, high_pc)) + if (!arange_add (unit, &func->arange, low_pc, high_pc)) goto fail; } @@ -2291,8 +2329,8 @@ scan_unit_for_symbols (struct comp_unit *unit) nested_funcs_size *= 2; tmp = (struct funcinfo **) - bfd_realloc (nested_funcs, - (nested_funcs_size * sizeof (struct funcinfo *))); + bfd_realloc (nested_funcs, + nested_funcs_size * sizeof (struct funcinfo *)); if (tmp == NULL) goto fail; nested_funcs = tmp; @@ -2338,6 +2376,7 @@ parse_comp_unit (struct dwarf2_debug *stash, bfd_vma low_pc = 0; bfd_vma high_pc = 0; bfd *abfd = stash->bfd_ptr; + bfd_boolean high_pc_relative = FALSE; version = read_2_bytes (abfd, info_ptr); info_ptr += 2; @@ -2352,23 +2391,29 @@ parse_comp_unit (struct dwarf2_debug *stash, if (version != 2 && version != 3 && version != 4) { - (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%u', this reader only handles version 2, 3 and 4 information."), version); + (*_bfd_error_handler) + (_("Dwarf Error: found dwarf version '%u', this reader" + " only handles version 2, 3 and 4 information."), version); bfd_set_error (bfd_error_bad_value); return 0; } if (addr_size > sizeof (bfd_vma)) { - (*_bfd_error_handler) (_("Dwarf Error: found address size '%u', this reader can not handle sizes greater than '%u'."), - addr_size, - (unsigned int) sizeof (bfd_vma)); + (*_bfd_error_handler) + (_("Dwarf Error: found address size '%u', this reader" + " can not handle sizes greater than '%u'."), + addr_size, + (unsigned int) sizeof (bfd_vma)); bfd_set_error (bfd_error_bad_value); return 0; } if (addr_size != 2 && addr_size != 4 && addr_size != 8) { - (*_bfd_error_handler) ("Dwarf Error: found address size '%u', this reader can only handle address sizes '2', '4' and '8'.", addr_size); + (*_bfd_error_handler) + ("Dwarf Error: found address size '%u', this reader" + " can only handle address sizes '2', '4' and '8'.", addr_size); bfd_set_error (bfd_error_bad_value); return 0; } @@ -2376,14 +2421,14 @@ parse_comp_unit (struct dwarf2_debug *stash, /* Read the abbrevs for this compilation unit into a table. */ abbrevs = read_abbrevs (abfd, abbrev_offset, stash); if (! abbrevs) - return 0; + return 0; abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; if (! abbrev_number) { (*_bfd_error_handler) (_("Dwarf Error: Bad abbrev number: %u."), - abbrev_number); + abbrev_number); bfd_set_error (bfd_error_bad_value); return 0; } @@ -2392,7 +2437,7 @@ parse_comp_unit (struct dwarf2_debug *stash, if (! abbrev) { (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."), - abbrev_number); + abbrev_number); bfd_set_error (bfd_error_bad_value); return 0; } @@ -2435,11 +2480,13 @@ parse_comp_unit (struct dwarf2_debug *stash, /* If the compilation unit DIE has a DW_AT_low_pc attribute, this is the base address to use when reading location lists or range lists. */ - unit->base_address = low_pc; + if (abbrev->tag == DW_TAG_compile_unit) + unit->base_address = low_pc; break; case DW_AT_high_pc: high_pc = attr.u.val; + high_pc_relative = attr.form != DW_FORM_addr; break; case DW_AT_ranges: @@ -2467,9 +2514,11 @@ parse_comp_unit (struct dwarf2_debug *stash, break; } } + if (high_pc_relative) + high_pc += low_pc; if (high_pc != 0) { - if (!arange_add (unit->abfd, &unit->arange, low_pc, high_pc)) + if (!arange_add (unit, &unit->arange, low_pc, high_pc)) return NULL; } @@ -2517,6 +2566,7 @@ comp_unit_find_nearest_line (struct comp_unit *unit, const char **filename_ptr, const char **functionname_ptr, unsigned int *linenumber_ptr, + unsigned int *discriminator_ptr, struct dwarf2_debug *stash) { bfd_boolean line_p; @@ -2557,7 +2607,8 @@ comp_unit_find_nearest_line (struct comp_unit *unit, stash->inliner_chain = function; line_p = lookup_address_in_line_info_table (unit->line_table, addr, filename_ptr, - linenumber_ptr); + linenumber_ptr, + discriminator_ptr); return line_p || func_p; } @@ -2739,25 +2790,43 @@ static asection * find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections, asection *after_sec) { - asection * msec; + asection *msec; + const char *look; + + if (after_sec == NULL) + { + look = debug_sections[debug_info].uncompressed_name; + msec = bfd_get_section_by_name (abfd, look); + if (msec != NULL) + return msec; + + look = debug_sections[debug_info].compressed_name; + if (look != NULL) + { + msec = bfd_get_section_by_name (abfd, look); + if (msec != NULL) + return msec; + } - msec = after_sec != NULL ? after_sec->next : abfd->sections; + for (msec = abfd->sections; msec != NULL; msec = msec->next) + if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO)) + return msec; - while (msec) + return NULL; + } + + for (msec = after_sec->next; msec != NULL; msec = msec->next) { - if (strcmp (msec->name, - debug_sections[debug_info].uncompressed_name) == 0) + look = debug_sections[debug_info].uncompressed_name; + if (strcmp (msec->name, look) == 0) return msec; - if (debug_sections[debug_info].compressed_name != NULL - && strcmp (msec->name, - debug_sections[debug_info].compressed_name) == 0) + look = debug_sections[debug_info].compressed_name; + if (look != NULL && strcmp (msec->name, look) == 0) return msec; if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO)) return msec; - - msec = msec->next; } return NULL; @@ -2831,7 +2900,7 @@ place_sections (bfd *abfd, struct dwarf2_debug *stash) } amt = i * sizeof (struct adjusted_section); - p = (struct adjusted_section *) bfd_zalloc (abfd, amt); + p = (struct adjusted_section *) bfd_alloc (abfd, amt); if (! p) return FALSE; @@ -2925,8 +2994,8 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table, && addr >= arange->low && addr < arange->high && (!best_fit - || ((arange->high - arange->low) - < (best_fit->arange.high - best_fit->arange.low)))) + || (arange->high - arange->low + < best_fit->arange.high - best_fit->arange.low))) best_fit = each_func; } } @@ -3117,6 +3186,122 @@ stash_find_line_fast (struct dwarf2_debug *stash, filename_ptr, linenumber_ptr); } +/* Read debug information from DEBUG_BFD when DEBUG_BFD is specified. + If DEBUG_BFD is not specified, we read debug information from ABFD + or its gnu_debuglink. The results will be stored in PINFO. + The function returns TRUE iff debug information is ready. */ + +bfd_boolean +_bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, + const struct dwarf_debug_section *debug_sections, + asymbol **symbols, + void **pinfo) +{ + bfd_size_type amt = sizeof (struct dwarf2_debug); + bfd_size_type total_size; + asection *msec; + struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; + + if (stash != NULL) + return TRUE; + + stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt); + if (! stash) + return FALSE; + stash->debug_sections = debug_sections; + stash->syms = symbols; + + *pinfo = stash; + + if (debug_bfd == NULL) + debug_bfd = abfd; + + msec = find_debug_info (debug_bfd, debug_sections, NULL); + if (msec == NULL && abfd == debug_bfd) + { + char * debug_filename = bfd_follow_gnu_debuglink (abfd, DEBUGDIR); + + if (debug_filename == NULL) + /* No dwarf2 info, and no gnu_debuglink to follow. + Note that at this point the stash has been allocated, but + contains zeros. This lets future calls to this function + fail more quickly. */ + return FALSE; + + if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL + || ! bfd_check_format (debug_bfd, bfd_object) + || (msec = find_debug_info (debug_bfd, + debug_sections, NULL)) == NULL) + { + if (debug_bfd) + bfd_close (debug_bfd); + /* FIXME: Should we report our failure to follow the debuglink ? */ + free (debug_filename); + return FALSE; + } + stash->close_on_cleanup = TRUE; + } + stash->bfd_ptr = debug_bfd; + + /* There can be more than one DWARF2 info section in a BFD these + days. First handle the easy case when there's only one. If + there's more than one, try case two: none of the sections is + compressed. In that case, read them all in and produce one + large stash. We do this in two passes - in the first pass we + just accumulate the section sizes, and in the second pass we + read in the section's contents. (The allows us to avoid + reallocing the data as we add sections to the stash.) If + some or all sections are compressed, then do things the slow + way, with a bunch of reallocs. */ + + if (! find_debug_info (debug_bfd, debug_sections, msec)) + { + /* Case 1: only one info section. */ + total_size = msec->size; + if (! read_section (debug_bfd, &stash->debug_sections[debug_info], + symbols, 0, + &stash->info_ptr_memory, &total_size)) + return FALSE; + } + else + { + /* Case 2: multiple sections. */ + for (total_size = 0; + msec; + msec = find_debug_info (debug_bfd, debug_sections, msec)) + total_size += msec->size; + + stash->info_ptr_memory = (bfd_byte *) bfd_malloc (total_size); + if (stash->info_ptr_memory == NULL) + return FALSE; + + total_size = 0; + for (msec = find_debug_info (debug_bfd, debug_sections, NULL); + msec; + msec = find_debug_info (debug_bfd, debug_sections, msec)) + { + bfd_size_type size; + + size = msec->size; + if (size == 0) + continue; + + if (!(bfd_simple_get_relocated_section_contents + (debug_bfd, msec, stash->info_ptr_memory + total_size, + symbols))) + return FALSE; + + total_size += size; + } + } + + stash->info_ptr = stash->info_ptr_memory; + stash->info_ptr_end = stash->info_ptr + total_size; + stash->sec = find_debug_info (debug_bfd, debug_sections, NULL); + stash->sec_info_ptr = stash->info_ptr; + return TRUE; +} + /* Find the source code location of SYMBOL. If SYMBOL is NULL then find the nearest source code location corresponding to the address SECTION + OFFSET. @@ -3139,6 +3324,7 @@ find_line (bfd *abfd, const char **filename_ptr, const char **functionname_ptr, unsigned int *linenumber_ptr, + unsigned int *discriminator_ptr, unsigned int addr_size, void **pinfo) { @@ -3157,17 +3343,18 @@ find_line (bfd *abfd, bfd_vma found = FALSE; bfd_boolean do_line; - stash = (struct dwarf2_debug *) *pinfo; + *filename_ptr = NULL; + if (functionname_ptr != NULL) + *functionname_ptr = NULL; + *linenumber_ptr = 0; + if (discriminator_ptr) + *discriminator_ptr = 0; - if (! stash) - { - bfd_size_type amt = sizeof (struct dwarf2_debug); + if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, + debug_sections, symbols, pinfo)) + return FALSE; - stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt); - if (! stash) - return FALSE; - stash->debug_sections = debug_sections; - } + stash = (struct dwarf2_debug *) *pinfo; /* In a relocatable file, 2 functions may have the same address. We change the section vma so that they won't overlap. */ @@ -3197,110 +3384,11 @@ find_line (bfd *abfd, addr += section->output_section->vma + section->output_offset; else addr += section->vma; - *filename_ptr = NULL; - if (! do_line) - *functionname_ptr = NULL; - *linenumber_ptr = 0; - - if (! *pinfo) - { - bfd *debug_bfd; - bfd_size_type total_size; - asection *msec; - - *pinfo = stash; - - msec = find_debug_info (abfd, debug_sections, NULL); - if (msec == NULL) - { - char * debug_filename = bfd_follow_gnu_debuglink (abfd, DEBUGDIR); - - if (debug_filename == NULL) - /* No dwarf2 info, and no gnu_debuglink to follow. - Note that at this point the stash has been allocated, but - contains zeros. This lets future calls to this function - fail more quickly. */ - goto done; - - if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL - || ! bfd_check_format (debug_bfd, bfd_object) - || (msec = find_debug_info (debug_bfd, - debug_sections, NULL)) == NULL) - { - if (debug_bfd) - bfd_close (debug_bfd); - /* FIXME: Should we report our failure to follow the debuglink ? */ - free (debug_filename); - goto done; - } - } - else - debug_bfd = abfd; - - /* There can be more than one DWARF2 info section in a BFD these - days. First handle the easy case when there's only one. If - there's more than one, try case two: none of the sections is - compressed. In that case, read them all in and produce one - large stash. We do this in two passes - in the first pass we - just accumulate the section sizes, and in the second pass we - read in the section's contents. (The allows us to avoid - reallocing the data as we add sections to the stash.) If - some or all sections are compressed, then do things the slow - way, with a bunch of reallocs. */ - - if (! find_debug_info (debug_bfd, debug_sections, msec)) - { - /* Case 1: only one info section. */ - total_size = msec->size; - if (! read_section (debug_bfd, &stash->debug_sections[debug_info], - symbols, 0, - &stash->info_ptr_memory, &total_size)) - goto done; - } - else - { - /* Case 2: multiple sections. */ - for (total_size = 0; - msec; - msec = find_debug_info (debug_bfd, debug_sections, msec)) - total_size += msec->size; - - stash->info_ptr_memory = (bfd_byte *) bfd_malloc (total_size); - if (stash->info_ptr_memory == NULL) - goto done; - - total_size = 0; - for (msec = find_debug_info (debug_bfd, debug_sections, NULL); - msec; - msec = find_debug_info (debug_bfd, debug_sections, msec)) - { - bfd_size_type size; - - size = msec->size; - if (size == 0) - continue; - - if (!(bfd_simple_get_relocated_section_contents - (debug_bfd, msec, stash->info_ptr_memory + total_size, - symbols))) - goto done; - - total_size += size; - } - } - - stash->info_ptr = stash->info_ptr_memory; - stash->info_ptr_end = stash->info_ptr + total_size; - stash->sec = find_debug_info (debug_bfd, debug_sections, NULL); - stash->sec_info_ptr = stash->info_ptr; - stash->syms = symbols; - stash->bfd_ptr = debug_bfd; - } /* A null info_ptr indicates that there is no dwarf2 info (or that an error occured while setting up the stash). */ if (! stash->info_ptr) - goto done; + return FALSE; stash->inliner_chain = NULL; @@ -3330,6 +3418,7 @@ find_line (bfd *abfd, /* Check the previously read comp. units first. */ for (each = stash->all_comp_units; each; each = each->next_unit) if ((symbol->flags & BSF_FUNCTION) == 0 + || each->arange.high == 0 || comp_unit_contains_address (each, addr)) { found = comp_unit_find_line (each, symbol, addr, filename_ptr, @@ -3343,11 +3432,13 @@ find_line (bfd *abfd, { for (each = stash->all_comp_units; each; each = each->next_unit) { - found = (comp_unit_contains_address (each, addr) + found = ((each->arange.high == 0 + || comp_unit_contains_address (each, addr)) && comp_unit_find_nearest_line (each, addr, filename_ptr, functionname_ptr, linenumber_ptr, + discriminator_ptr, stash)); if (found) goto done; @@ -3417,10 +3508,10 @@ find_line (bfd *abfd, stash->all_comp_units->prev_unit = each; else stash->last_comp_unit = each; - + each->next_unit = stash->all_comp_units; stash->all_comp_units = each; - + /* DW_AT_low_pc and DW_AT_high_pc are optional for compilation units. If we don't have them (i.e., unit->high == 0), we need to consult the line info table @@ -3441,6 +3532,7 @@ find_line (bfd *abfd, filename_ptr, functionname_ptr, linenumber_ptr, + discriminator_ptr, stash)); if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr) @@ -3456,7 +3548,7 @@ find_line (bfd *abfd, } } -done: + done: if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) unset_sections (stash); @@ -3475,12 +3567,13 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, const char **filename_ptr, const char **functionname_ptr, unsigned int *linenumber_ptr, + unsigned int *discriminator_ptr, unsigned int addr_size, void **pinfo) { return find_line (abfd, debug_sections, section, offset, NULL, symbols, - filename_ptr, functionname_ptr, linenumber_ptr, addr_size, - pinfo); + filename_ptr, functionname_ptr, linenumber_ptr, + discriminator_ptr, addr_size, pinfo); } /* The DWARF2 version of find_line. @@ -3492,11 +3585,13 @@ _bfd_dwarf2_find_line (bfd *abfd, asymbol *symbol, const char **filename_ptr, unsigned int *linenumber_ptr, + unsigned int *discriminator_ptr, unsigned int addr_size, void **pinfo) { return find_line (abfd, dwarf_debug_sections, NULL, 0, symbol, symbols, - filename_ptr, NULL, linenumber_ptr, addr_size, pinfo); + filename_ptr, NULL, linenumber_ptr, discriminator_ptr, + addr_size, pinfo); } bfd_boolean @@ -3527,17 +3622,12 @@ _bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED, } void -_bfd_dwarf2_cleanup_debug_info (bfd *abfd) +_bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo) { + struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; struct comp_unit *each; - struct dwarf2_debug *stash; - - if (abfd == NULL || elf_tdata (abfd) == NULL) - return; - - stash = (struct dwarf2_debug *) elf_tdata (abfd)->dwarf2_find_line_info; - if (stash == NULL) + if (abfd == NULL || stash == NULL) return; for (each = stash->all_comp_units; each; each = each->next_unit) @@ -3602,4 +3692,6 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd) free (stash->dwarf_ranges_buffer); if (stash->info_ptr_memory) free (stash->info_ptr_memory); + if (stash->close_on_cleanup) + bfd_close (stash->bfd_ptr); } diff --git a/contrib/gdb-7/bfd/elf-attrs.c b/contrib/gdb-7/bfd/elf-attrs.c index 569e846cc5..9a6ff6f910 100644 --- a/contrib/gdb-7/bfd/elf-attrs.c +++ b/contrib/gdb-7/bfd/elf-attrs.c @@ -1,5 +1,5 @@ /* ELF attributes support (based on ARM EABI attributes). - Copyright 2005, 2006, 2007, 2009, 2010 + Copyright 2005, 2006, 2007, 2009, 2010, 2012 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -347,6 +347,10 @@ _bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd) int i; int vendor; + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return; + for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) { in_attr @@ -428,7 +432,7 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) bfd_byte *contents; bfd_byte *p; bfd_vma len; - const char *std_section; + const char *std_sec; contents = (bfd_byte *) bfd_malloc (hdr->sh_size); if (!contents) @@ -440,7 +444,7 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) return; } p = contents; - std_section = get_elf_backend_data (abfd)->obj_attrs_vendor; + std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor; if (*(p++) == 'A') { len = hdr->sh_size - 1; @@ -455,11 +459,11 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) if (section_len > len) section_len = len; len -= section_len; - namelen = strlen ((char *)p) + 1; + namelen = strlen ((char *) p) + 1; section_len -= namelen + 4; - if (std_section && strcmp ((char *)p, std_section) == 0) + if (std_sec && strcmp ((char *) p, std_sec) == 0) vendor = OBJ_ATTR_PROC; - else if (strcmp ((char *)p, "gnu") == 0) + else if (strcmp ((char *) p, "gnu") == 0) vendor = OBJ_ATTR_GNU; else { diff --git a/contrib/gdb-7/bfd/elf-bfd.h b/contrib/gdb-7/bfd/elf-bfd.h index 486b76eecf..3f068bb95e 100644 --- a/contrib/gdb-7/bfd/elf-bfd.h +++ b/contrib/gdb-7/bfd/elf-bfd.h @@ -1,7 +1,5 @@ /* BFD back-end data structures for ELF files. - Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright 1992-2013 Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -191,8 +189,8 @@ struct elf_link_hash_entry FIXME: There is no real need for this field if def_dynamic is never cleared and all places that test def_dynamic also test def_regular. */ unsigned int dynamic_def : 1; - /* Symbol is weak in all shared objects. */ - unsigned int dynamic_weak : 1; + /* Symbol has a non-weak reference from a shared object. */ + unsigned int ref_dynamic_nonweak : 1; /* Symbol is referenced with a relocation where C/C++ pointer equality matters. */ unsigned int pointer_equality_needed : 1; @@ -402,7 +400,8 @@ struct eh_frame_hdr_info one line. */ enum elf_target_id { - ALPHA_ELF_DATA = 1, + AARCH64_ELF_DATA = 1, + ALPHA_ELF_DATA, ARM_ELF_DATA, AVR_ELF_DATA, BFIN_ELF_DATA, @@ -416,9 +415,11 @@ enum elf_target_id M32R_ELF_DATA, M68HC11_ELF_DATA, M68K_ELF_DATA, + METAG_ELF_DATA, MICROBLAZE_ELF_DATA, MIPS_ELF_DATA, MN10300_ELF_DATA, + NIOS2_ELF_DATA, PPC32_ELF_DATA, PPC64_ELF_DATA, S390_ELF_DATA, @@ -428,6 +429,7 @@ enum elf_target_id TIC6X_ELF_DATA, X86_64_ELF_DATA, XTENSA_ELF_DATA, + XGATE_ELF_DATA, TILEGX_ELF_DATA, TILEPRO_ELF_DATA, GENERIC_ELF_DATA @@ -496,6 +498,9 @@ struct elf_link_hash_table /* The _PROCEDURE_LINKAGE_TABLE_ symbol. */ struct elf_link_hash_entry *hplt; + /* The _DYNAMIC symbol. */ + struct elf_link_hash_entry *hdynamic; + /* A pointer to information used to merge SEC_MERGE sections. */ void *merge_info; @@ -1185,7 +1190,8 @@ struct elf_backend_data see elf.c, elfcode.h. */ bfd *(*elf_backend_bfd_from_remote_memory) (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); + int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, + bfd_size_type len)); /* This function is used by `_bfd_elf_get_synthetic_symtab'; see elf.c. */ @@ -1221,6 +1227,12 @@ struct elf_backend_data /* Return TRUE if type is a function symbol type. */ bfd_boolean (*is_function_type) (unsigned int type); + /* If the ELF symbol SYM might be a function in SEC, return the + function size and set *CODE_OFF to the function's entry point, + otherwise return zero. */ + bfd_size_type (*maybe_function_sym) (const asymbol *sym, asection *sec, + bfd_vma *code_off); + /* Used to handle bad SHF_LINK_ORDER input. */ bfd_error_handler_type link_order_error_handler; @@ -1273,6 +1285,9 @@ struct elf_backend_data /* This is non-zero if static TLS segments require a special alignment. */ unsigned static_tls_alignment; + /* Alignment for the PT_GNU_STACK segment. */ + unsigned stack_align; + /* This is TRUE if the linker should act like collect and gather global constructors and destructors by name. This is TRUE for MIPS ELF because the Irix 5 tools can not handle the .init @@ -1361,6 +1376,9 @@ struct bfd_elf_section_data /* The ELF header for this section. */ Elf_Internal_Shdr this_hdr; + /* INPUT_SECTION_FLAGS if specified in the linker script. */ + struct flag_info *section_flag_info; + /* Information about the REL and RELA reloc sections associated with this section, if any. */ struct bfd_elf_section_reloc_data rel, rela; @@ -1413,14 +1431,14 @@ struct bfd_elf_section_data void *sec_info; }; -#define elf_section_data(sec) ((struct bfd_elf_section_data*)(sec)->used_by_bfd) +#define elf_section_data(sec) ((struct bfd_elf_section_data*)(sec)->used_by_bfd) #define elf_linked_to_section(sec) (elf_section_data(sec)->linked_to) -#define elf_section_type(sec) (elf_section_data(sec)->this_hdr.sh_type) -#define elf_section_flags(sec) (elf_section_data(sec)->this_hdr.sh_flags) -#define elf_group_name(sec) (elf_section_data(sec)->group.name) -#define elf_group_id(sec) (elf_section_data(sec)->group.id) -#define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group) -#define elf_fde_list(sec) (elf_section_data(sec)->fde_list) +#define elf_section_type(sec) (elf_section_data(sec)->this_hdr.sh_type) +#define elf_section_flags(sec) (elf_section_data(sec)->this_hdr.sh_flags) +#define elf_group_name(sec) (elf_section_data(sec)->group.name) +#define elf_group_id(sec) (elf_section_data(sec)->group.id) +#define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group) +#define elf_fde_list(sec) (elf_section_data(sec)->fde_list) #define elf_sec_group(sec) (elf_section_data(sec)->sec_group) #define xvec_get_elf_backend_data(xvec) \ @@ -1492,6 +1510,64 @@ struct sdt_note bfd_byte data[1]; }; +/* NT_GNU_BUILD_ID note type info for input BFDs. */ +struct elf_build_id +{ + size_t size; + bfd_byte data[1]; +}; + +/* tdata information grabbed from an elf core file. */ +struct core_elf_obj_tdata +{ + int signal; + int pid; + int lwpid; + char* program; + char* command; +}; + +/* Extra tdata information held for output ELF BFDs. */ +struct output_elf_obj_tdata +{ + struct elf_segment_map *seg_map; + struct elf_strtab_hash *strtab_ptr; + + /* STT_SECTION symbols for each section */ + asymbol **section_syms; + + /* Used to determine if PT_GNU_EH_FRAME segment header should be + created. */ + asection *eh_frame_hdr; + + /* NT_GNU_BUILD_ID note type info. */ + struct + { + bfd_boolean (*after_write_object_contents) (bfd *); + const char *style; + asection *sec; + } build_id; + + /* Records the result of `get_program_header_size'. */ + bfd_size_type program_header_size; + + /* Used when laying out sections. */ + file_ptr next_file_pos; + + int num_section_syms; + unsigned int shstrtab_section, strtab_section; + + /* Segment flags for the PT_GNU_STACK segment. */ + unsigned int stack_flags; + + /* This is set to TRUE if the object was created by the backend + linker. */ + bfd_boolean linker; + + /* Used to determine if the e_flags field has been initialized */ + bfd_boolean flags_init; +}; + /* Some private data is stashed away for future use using the tdata pointer in the bfd structure. */ @@ -1500,13 +1576,6 @@ struct elf_obj_tdata Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */ Elf_Internal_Shdr **elf_sect_ptr; Elf_Internal_Phdr *phdr; - struct elf_segment_map *segment_map; - struct elf_strtab_hash *strtab_ptr; - int num_locals; - int num_globals; - unsigned int num_elf_sections; /* elf_sect_ptr size */ - int num_section_syms; - asymbol **section_syms; /* STT_SECTION symbols for each section */ Elf_Internal_Shdr symtab_hdr; Elf_Internal_Shdr shstrtab_hdr; Elf_Internal_Shdr strtab_hdr; @@ -1516,20 +1585,9 @@ struct elf_obj_tdata Elf_Internal_Shdr dynverref_hdr; Elf_Internal_Shdr dynverdef_hdr; Elf_Internal_Shdr symtab_shndx_hdr; - unsigned int symtab_section, shstrtab_section; - unsigned int strtab_section, dynsymtab_section; - unsigned int symtab_shndx_section; - unsigned int dynversym_section, dynverdef_section, dynverref_section; - file_ptr next_file_pos; bfd_vma gp; /* The gp value */ unsigned int gp_size; /* The gp size */ - - /* Information grabbed from an elf core file. */ - int core_signal; - int core_pid; - int core_lwpid; - char* core_program; - char* core_command; + unsigned int num_elf_sections; /* elf_sect_ptr size */ /* A mapping from external symbols to entries in the linker hash table, used when linking. This is indexed by the symbol index @@ -1560,36 +1618,17 @@ struct elf_obj_tdata are used by a dynamic object. */ const char *dt_audit; - /* Records the result of `get_program_header_size'. */ - bfd_size_type program_header_size; - /* Used by find_nearest_line entry point. */ void *line_info; - /* Used by MIPS ELF find_nearest_line entry point. The structure - could be included directly in this one, but there's no point to - wasting the memory just for the infrequently called - find_nearest_line. */ - struct mips_elf_find_line *find_line_info; - /* A place to stash dwarf1 info for this bfd. */ struct dwarf1_debug *dwarf1_find_line_info; /* A place to stash dwarf2 info for this bfd. */ void *dwarf2_find_line_info; - /* An array of stub sections indexed by symbol number, used by the - MIPS ELF linker. FIXME: We should figure out some way to only - include this field for a MIPS ELF target. */ - asection **local_stubs; - asection **local_call_stubs; - - /* Used to determine if PT_GNU_EH_FRAME segment header should be - created. */ - asection *eh_frame_hdr; - - Elf_Internal_Shdr **group_sect_ptr; - int num_group; + /* Stash away info for yet another find line/function variant. */ + void *elf_find_function_cache; /* Number of symbol version definitions we are about to emit. */ unsigned int cverdefs; @@ -1597,83 +1636,80 @@ struct elf_obj_tdata /* Number of symbol version references we are about to emit. */ unsigned int cverrefs; - /* Segment flags for the PT_GNU_STACK segment. */ - unsigned int stack_flags; - /* Symbol version definitions in external objects. */ Elf_Internal_Verdef *verdef; /* Symbol version references to external objects. */ Elf_Internal_Verneed *verref; - /* The Irix 5 support uses two virtual sections, which represent - text/data symbols defined in dynamic objects. */ - asymbol *elf_data_symbol; - asymbol *elf_text_symbol; - asection *elf_data_section; - asection *elf_text_section; - /* A pointer to the .eh_frame section. */ asection *eh_frame_section; - /* Whether a dyanmic object was specified normally on the linker - command line, or was specified when --as-needed was in effect, - or was found via a DT_NEEDED entry. */ - enum dynamic_lib_link_class dyn_lib_class; - - /* This is set to TRUE if the object was created by the backend - linker. */ - bfd_boolean linker; - - /* Irix 5 often screws up the symbol table, sorting local symbols - after global symbols. This flag is set if the symbol table in - this BFD appears to be screwed up. If it is, we ignore the - sh_info field in the symbol table header, and always read all the - symbols. */ - bfd_boolean bad_symtab; - - /* Used to determine if the e_flags field has been initialized */ - bfd_boolean flags_init; - /* Symbol buffer. */ void *symbuf; obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES]; obj_attribute_list *other_obj_attributes[2]; - /* Called at the end of _bfd_elf_write_object_contents if not NULL. */ - bfd_boolean (*after_write_object_contents) (bfd *); - void *after_write_object_contents_info; - /* NT_GNU_BUILD_ID note type. */ - bfd_size_type build_id_size; - bfd_byte *build_id; + struct elf_build_id *build_id; /* Linked-list containing information about every Systemtap section found in the object file. Each section corresponds to one entry in the list. */ struct sdt_note *sdt_note_head; + Elf_Internal_Shdr **group_sect_ptr; + int num_group; + + unsigned int symtab_section, symtab_shndx_section, dynsymtab_section; + unsigned int dynversym_section, dynverdef_section, dynverref_section; + + /* An identifier used to distinguish different target + specific extensions to this structure. */ + enum elf_target_id object_id; + + /* Whether a dyanmic object was specified normally on the linker + command line, or was specified when --as-needed was in effect, + or was found via a DT_NEEDED entry. */ + enum dynamic_lib_link_class dyn_lib_class; + + /* Irix 5 often screws up the symbol table, sorting local symbols + after global symbols. This flag is set if the symbol table in + this BFD appears to be screwed up. If it is, we ignore the + sh_info field in the symbol table header, and always read all the + symbols. */ + bfd_boolean bad_symtab; + /* True if the bfd contains symbols that have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE binding. Used to set the osabi field in the ELF header structure. */ bfd_boolean has_gnu_symbols; - /* An identifier used to distinguish different target - specific extensions to this structure. */ - enum elf_target_id object_id; + /* Information grabbed from an elf core file. */ + struct core_elf_obj_tdata *core; + + /* More information held for output ELF BFDs. */ + struct output_elf_obj_tdata *o; }; #define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) #define elf_object_id(bfd) (elf_tdata(bfd) -> object_id) -#define elf_program_header_size(bfd) (elf_tdata(bfd) -> program_header_size) +#define elf_program_header_size(bfd) (elf_tdata(bfd) -> o->program_header_size) #define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header) #define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr) #define elf_numsections(bfd) (elf_tdata(bfd) -> num_elf_sections) -#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr) +#define elf_seg_map(bfd) (elf_tdata(bfd) -> o->seg_map) +#define elf_next_file_pos(bfd) (elf_tdata(bfd) -> o->next_file_pos) +#define elf_eh_frame_hdr(bfd) (elf_tdata(bfd) -> o->eh_frame_hdr) +#define elf_linker(bfd) (elf_tdata(bfd) -> o->linker) +#define elf_stack_flags(bfd) (elf_tdata(bfd) -> o->stack_flags) +#define elf_shstrtab(bfd) (elf_tdata(bfd) -> o->strtab_ptr) #define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section) #define elf_symtab_shndx(bfd) (elf_tdata(bfd) -> symtab_shndx_section) +#define elf_strtab_sec(bfd) (elf_tdata(bfd) -> o->strtab_section) +#define elf_shstrtab_sec(bfd) (elf_tdata(bfd) -> o->shstrtab_section) #define elf_symtab_hdr(bfd) (elf_tdata(bfd) -> symtab_hdr) #define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section) #define elf_dynversym(bfd) (elf_tdata(bfd) -> dynversym_section) @@ -1681,10 +1717,8 @@ struct elf_obj_tdata #define elf_dynverref(bfd) (elf_tdata(bfd) -> dynverref_section) #define elf_eh_frame_section(bfd) \ (elf_tdata(bfd) -> eh_frame_section) -#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals) -#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals) -#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms) -#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> num_section_syms) +#define elf_section_syms(bfd) (elf_tdata(bfd) -> o->section_syms) +#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> o->num_section_syms) #define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo) #define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus) #define elf_gp(bfd) (elf_tdata(bfd) -> gp) @@ -1697,7 +1731,7 @@ struct elf_obj_tdata #define elf_dt_audit(bfd) (elf_tdata(bfd) -> dt_audit) #define elf_dyn_lib_class(bfd) (elf_tdata(bfd) -> dyn_lib_class) #define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) -#define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init) +#define elf_flags_init(bfd) (elf_tdata(bfd) -> o->flags_init) #define elf_known_obj_attributes(bfd) (elf_tdata (bfd) -> known_obj_attributes) #define elf_other_obj_attributes(bfd) (elf_tdata (bfd) -> other_obj_attributes) #define elf_known_obj_attributes_proc(bfd) \ @@ -1781,6 +1815,8 @@ extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create (bfd *); +extern void _bfd_elf_link_hash_table_free + (struct bfd_link_hash_table *); extern void _bfd_elf_link_hash_copy_indirect (struct bfd_link_info *, struct elf_link_hash_entry *, struct elf_link_hash_entry *); @@ -1807,8 +1843,7 @@ extern void bfd_elf_set_group_contents (bfd *, asection *, void *); extern asection *_bfd_elf_check_kept_section (asection *, struct bfd_link_info *); -extern void _bfd_elf_link_just_syms - (asection *, struct bfd_link_info *); +#define _bfd_elf_link_just_syms _bfd_generic_link_just_syms extern void _bfd_elf_copy_link_hash_symbol_type (bfd *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *); extern bfd_boolean _bfd_elf_size_group_sections @@ -1866,9 +1901,16 @@ extern bfd_boolean _bfd_elf_set_arch_mach extern bfd_boolean _bfd_elf_find_nearest_line (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, unsigned int *); +extern bfd_boolean _bfd_elf_find_nearest_line_discriminator + (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, + unsigned int *, unsigned int *); extern bfd_boolean _bfd_elf_find_line (bfd *, asymbol **, asymbol *, const char **, unsigned int *); +extern bfd_boolean _bfd_elf_find_line_discriminator + (bfd *, asymbol **, asymbol *, const char **, unsigned int *, unsigned int *); #define _bfd_generic_find_line _bfd_elf_find_line +#define _bfd_generic_find_nearest_line_discriminator \ + _bfd_elf_find_nearest_line_discriminator extern bfd_boolean _bfd_elf_find_inliner_info (bfd *, const char **, const char **, unsigned int *); #define _bfd_elf_read_minisymbols _bfd_generic_read_minisymbols @@ -1913,8 +1955,12 @@ extern void _bfd_elf_strtab_addref (struct elf_strtab_hash *, bfd_size_type); extern void _bfd_elf_strtab_delref (struct elf_strtab_hash *, bfd_size_type); +extern unsigned int _bfd_elf_strtab_refcount + (struct elf_strtab_hash *, bfd_size_type); extern void _bfd_elf_strtab_clear_all_refs - (struct elf_strtab_hash *); + (struct elf_strtab_hash *tab); +extern void _bfd_elf_strtab_restore_size + (struct elf_strtab_hash *, bfd_size_type); extern bfd_size_type _bfd_elf_strtab_size (struct elf_strtab_hash *); extern bfd_size_type _bfd_elf_strtab_offset @@ -1942,12 +1988,14 @@ extern bfd_boolean _bfd_elf_write_section_eh_frame (bfd *, struct bfd_link_info *, asection *, bfd_byte *); extern bfd_boolean _bfd_elf_write_section_eh_frame_hdr (bfd *, struct bfd_link_info *); +extern bfd_boolean _bfd_elf_eh_frame_present + (struct bfd_link_info *); extern bfd_boolean _bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *); extern bfd_boolean _bfd_elf_merge_symbol (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *, - asection **, bfd_vma *, unsigned int *, + asection **, bfd_vma *, bfd_boolean *, unsigned int *, struct elf_link_hash_entry **, bfd_boolean *, bfd_boolean *, bfd_boolean *, bfd_boolean *); @@ -2132,9 +2180,6 @@ extern unsigned int _bfd_elf_common_section_index extern asection *_bfd_elf_common_section (asection *); -extern void _bfd_dwarf2_cleanup_debug_info - (bfd *); - extern bfd_vma _bfd_elf_default_got_elt_size (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, bfd *, unsigned long); @@ -2200,10 +2245,13 @@ extern bfd_boolean _bfd_elf_map_sections_to_segments extern bfd_boolean _bfd_elf_is_function_type (unsigned int); +extern bfd_size_type _bfd_elf_maybe_function_sym (const asymbol *, asection *, + bfd_vma *); + extern int bfd_elf_get_default_section_type (flagword); -extern void bfd_elf_lookup_section_flags - (struct bfd_link_info *, struct flag_info *); +extern bfd_boolean bfd_elf_lookup_section_flags + (struct bfd_link_info *, struct flag_info *, asection *); extern Elf_Internal_Phdr * _bfd_elf_find_segment_containing_section (bfd * abfd, asection * section); @@ -2241,19 +2289,63 @@ extern char *elfcore_write_s390_last_break (bfd *, char *, int *, const void *, int); extern char *elfcore_write_s390_system_call (bfd *, char *, int *, const void *, int); +extern char *elfcore_write_s390_tdb + (bfd *, char *, int *, const void *, int); extern char *elfcore_write_arm_vfp (bfd *, char *, int *, const void *, int); +extern char *elfcore_write_aarch_tls + (bfd *, char *, int *, const void *, int); +extern char *elfcore_write_aarch_hw_break + (bfd *, char *, int *, const void *, int); +extern char *elfcore_write_aarch_hw_watch + (bfd *, char *, int *, const void *, int); extern char *elfcore_write_lwpstatus (bfd *, char *, int *, long, int, const void *); extern char *elfcore_write_register_note (bfd *, char *, int *, const char *, const void *, int); +/* Internal structure which holds information to be included in the + PRPSINFO section of Linux core files. + + This is an "internal" structure in the sense that it should be used + to pass information to BFD (via the `elfcore_write_linux_prpsinfo' + function), so things like endianess shouldn't be an issue. This + structure will eventually be converted in one of the + `elf_external_linux_*' structures and written out to an output bfd + by one of the functions declared below. */ + +struct elf_internal_linux_prpsinfo + { + char pr_state; /* Numeric process state. */ + char pr_sname; /* Char for pr_state. */ + char pr_zomb; /* Zombie. */ + char pr_nice; /* Nice val. */ + unsigned long pr_flag; /* Flags. */ + unsigned int pr_uid; + unsigned int pr_gid; + int pr_pid, pr_ppid, pr_pgrp, pr_sid; + char pr_fname[16 + 1]; /* Filename of executable. */ + char pr_psargs[80 + 1]; /* Initial part of arg list. */ + }; + +/* Linux/most 32-bit archs. */ +extern char *elfcore_write_linux_prpsinfo32 + (bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *); + +/* Linux/most 64-bit archs. */ +extern char *elfcore_write_linux_prpsinfo64 + (bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *); + +/* Linux/PPC32 uses different layout compared to most archs. */ +extern char *elfcore_write_ppc_linux_prpsinfo32 + (bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *); + extern bfd *_bfd_elf32_bfd_from_remote_memory (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma, bfd_byte *, int)); + int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)); extern bfd *_bfd_elf64_bfd_from_remote_memory (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma, bfd_byte *, int)); + int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)); extern bfd_vma bfd_elf_obj_attr_size (bfd *); extern void bfd_elf_set_obj_attr_contents (bfd *, bfd_byte *, bfd_vma); @@ -2403,10 +2495,12 @@ extern asection _bfd_elf_large_com_section; link, we remove such relocations. Otherwise, we just want the section contents zeroed and avoid any special processing. */ #define RELOC_AGAINST_DISCARDED_SECTION(info, input_bfd, input_section, \ - rel, relend, howto, contents) \ + rel, count, relend, \ + howto, index, contents) \ { \ + int i_; \ _bfd_clear_contents (howto, input_bfd, input_section, \ - contents + rel->r_offset); \ + contents + rel[index].r_offset); \ \ if (info->relocatable \ && (input_section->flags & SEC_DEBUGGING)) \ @@ -2418,27 +2512,32 @@ extern asection _bfd_elf_large_com_section; rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); \ \ /* Avoid empty output section. */ \ - if (rel_hdr->sh_size > rel_hdr->sh_entsize) \ + if (rel_hdr->sh_size > count * rel_hdr->sh_entsize) \ { \ - rel_hdr->sh_size -= rel_hdr->sh_entsize; \ + rel_hdr->sh_size -= count * rel_hdr->sh_entsize; \ rel_hdr = _bfd_elf_single_rel_hdr (input_section); \ - rel_hdr->sh_size -= rel_hdr->sh_entsize; \ + rel_hdr->sh_size -= count * rel_hdr->sh_entsize; \ \ - memmove (rel, rel + 1, (relend - rel - 1) * sizeof (*rel)); \ + memmove (rel, rel + count, \ + (relend - rel - count) * sizeof (*rel)); \ \ - input_section->reloc_count--; \ - relend--; \ + input_section->reloc_count -= count; \ + relend -= count; \ rel--; \ continue; \ } \ } \ \ - rel->r_info = 0; \ - rel->r_addend = 0; \ + for (i_ = 0; i_ < count; i_++) \ + { \ + rel[i_].r_info = 0; \ + rel[i_].r_addend = 0; \ + } \ + rel += count - 1; \ continue; \ } -/* Will a symbol be bound to the the definition within the shared +/* Will a symbol be bound to the definition within the shared library, if any. A unique symbol can never be bound locally. */ #define SYMBOLIC_BIND(INFO, H) \ (!(H)->unique_global \ diff --git a/contrib/gdb-7/bfd/elf-eh-frame.c b/contrib/gdb-7/bfd/elf-eh-frame.c index 54142b2952..832a99192d 100644 --- a/contrib/gdb-7/bfd/elf-eh-frame.c +++ b/contrib/gdb-7/bfd/elf-eh-frame.c @@ -1,6 +1,6 @@ /* .eh_frame section optimization. - Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Written by Jakub Jelinek . This file is part of BFD, the Binary File Descriptor library. @@ -491,7 +491,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, return; if (sec->size == 0 - || sec->sec_info_type != ELF_INFO_TYPE_NONE) + || sec->sec_info_type != SEC_INFO_TYPE_NONE) { /* This file does not contain .eh_frame information. */ return; @@ -904,7 +904,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, BFD_ASSERT (cie_count == num_cies); elf_section_data (sec)->sec_info = sec_info; - sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; + sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME; if (hdr_info->merge_cies) { sec_info->cies = local_cies; @@ -1137,7 +1137,7 @@ _bfd_elf_discard_section_eh_frame struct eh_frame_hdr_info *hdr_info; unsigned int ptr_size, offset; - if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) + if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) return FALSE; sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; @@ -1243,10 +1243,30 @@ _bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) if (hdr_info->table) sec->size += 4 + hdr_info->fde_count * 8; - elf_tdata (abfd)->eh_frame_hdr = sec; + elf_eh_frame_hdr (abfd) = sec; return TRUE; } +/* Return true if there is at least one non-empty .eh_frame section in + input files. Can only be called after ld has mapped input to + output sections, and before sections are stripped. */ +bfd_boolean +_bfd_elf_eh_frame_present (struct bfd_link_info *info) +{ + asection *eh = bfd_get_section_by_name (info->output_bfd, ".eh_frame"); + + if (eh == NULL) + return FALSE; + + /* Count only sections which have at least a single CIE or FDE. + There cannot be any CIE or FDE <= 8 bytes. */ + for (eh = eh->map_head.s; eh != NULL; eh = eh->map_head.s) + if (eh->size > 8) + return TRUE; + + return FALSE; +} + /* This function is called from size_dynamic_sections. It needs to decide whether .eh_frame_hdr should be output or not, because when the dynamic symbol table has been sized it is too late @@ -1255,8 +1275,6 @@ _bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) bfd_boolean _bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) { - asection *o; - bfd *abfd; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; @@ -1265,24 +1283,9 @@ _bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) if (hdr_info->hdr_sec == NULL) return TRUE; - if (bfd_is_abs_section (hdr_info->hdr_sec->output_section)) - { - hdr_info->hdr_sec = NULL; - return TRUE; - } - - abfd = NULL; - if (info->eh_frame_hdr) - for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) - { - /* Count only sections which have at least a single CIE or FDE. - There cannot be any CIE or FDE <= 8 bytes. */ - o = bfd_get_section_by_name (abfd, ".eh_frame"); - if (o && o->size > 8 && !bfd_is_abs_section (o->output_section)) - break; - } - - if (abfd == NULL) + if (bfd_is_abs_section (hdr_info->hdr_sec->output_section) + || !info->eh_frame_hdr + || !_bfd_elf_eh_frame_present (info)) { hdr_info->hdr_sec->flags |= SEC_EXCLUDE; hdr_info->hdr_sec = NULL; @@ -1307,7 +1310,7 @@ _bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, struct eh_frame_sec_info *sec_info; unsigned int lo, hi, mid; - if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) + if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) return offset; sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; @@ -1395,7 +1398,7 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, unsigned int ptr_size; struct eh_cie_fde *ent; - if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) + if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) /* FIXME: octets_per_byte. */ return bfd_set_section_contents (abfd, sec->output_section, contents, sec->output_offset, sec->size); @@ -1767,74 +1770,81 @@ _bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; asection *sec; - bfd_byte *contents; - asection *eh_frame_sec; - bfd_size_type size; - bfd_boolean retval; - bfd_vma encoded_eh_frame; + bfd_boolean retval = TRUE; htab = elf_hash_table (info); hdr_info = &htab->eh_info; sec = hdr_info->hdr_sec; - if (sec == NULL) - return TRUE; - size = EH_FRAME_HDR_SIZE; - if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) - size += 4 + hdr_info->fde_count * 8; - contents = (bfd_byte *) bfd_malloc (size); - if (contents == NULL) - return FALSE; - - eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); - if (eh_frame_sec == NULL) + if (info->eh_frame_hdr && sec != NULL) { - free (contents); - return FALSE; - } + bfd_byte *contents; + asection *eh_frame_sec; + bfd_size_type size; + bfd_vma encoded_eh_frame; + + size = EH_FRAME_HDR_SIZE; + if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) + size += 4 + hdr_info->fde_count * 8; + contents = (bfd_byte *) bfd_malloc (size); + if (contents == NULL) + return FALSE; - memset (contents, 0, EH_FRAME_HDR_SIZE); - contents[0] = 1; /* Version. */ - contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address - (abfd, info, eh_frame_sec, 0, sec, 4, - &encoded_eh_frame); /* .eh_frame offset. */ + eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); + if (eh_frame_sec == NULL) + { + free (contents); + return FALSE; + } - if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) - { - contents[2] = DW_EH_PE_udata4; /* FDE count encoding. */ - contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* Search table enc. */ - } - else - { - contents[2] = DW_EH_PE_omit; - contents[3] = DW_EH_PE_omit; - } - bfd_put_32 (abfd, encoded_eh_frame, contents + 4); + memset (contents, 0, EH_FRAME_HDR_SIZE); + /* Version. */ + contents[0] = 1; + /* .eh_frame offset. */ + contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address + (abfd, info, eh_frame_sec, 0, sec, 4, &encoded_eh_frame); - if (contents[2] != DW_EH_PE_omit) - { - unsigned int i; + if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) + { + /* FDE count encoding. */ + contents[2] = DW_EH_PE_udata4; + /* Search table encoding. */ + contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; + } + else + { + contents[2] = DW_EH_PE_omit; + contents[3] = DW_EH_PE_omit; + } + bfd_put_32 (abfd, encoded_eh_frame, contents + 4); - bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE); - qsort (hdr_info->array, hdr_info->fde_count, sizeof (*hdr_info->array), - vma_compare); - for (i = 0; i < hdr_info->fde_count; i++) + if (contents[2] != DW_EH_PE_omit) { - bfd_put_32 (abfd, - hdr_info->array[i].initial_loc - - sec->output_section->vma, - contents + EH_FRAME_HDR_SIZE + i * 8 + 4); - bfd_put_32 (abfd, - hdr_info->array[i].fde - sec->output_section->vma, - contents + EH_FRAME_HDR_SIZE + i * 8 + 8); + unsigned int i; + + bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE); + qsort (hdr_info->array, hdr_info->fde_count, + sizeof (*hdr_info->array), vma_compare); + for (i = 0; i < hdr_info->fde_count; i++) + { + bfd_put_32 (abfd, + hdr_info->array[i].initial_loc + - sec->output_section->vma, + contents + EH_FRAME_HDR_SIZE + i * 8 + 4); + bfd_put_32 (abfd, + hdr_info->array[i].fde - sec->output_section->vma, + contents + EH_FRAME_HDR_SIZE + i * 8 + 8); + } } - } - /* FIXME: octets_per_byte. */ - retval = bfd_set_section_contents (abfd, sec->output_section, - contents, (file_ptr) sec->output_offset, - sec->size); - free (contents); + /* FIXME: octets_per_byte. */ + retval = bfd_set_section_contents (abfd, sec->output_section, contents, + (file_ptr) sec->output_offset, + sec->size); + free (contents); + } + if (hdr_info->array != NULL) + free (hdr_info->array); return retval; } diff --git a/contrib/gdb-7/bfd/elf-ifunc.c b/contrib/gdb-7/bfd/elf-ifunc.c index 3ba96c7961..e56427deff 100644 --- a/contrib/gdb-7/bfd/elf-ifunc.c +++ b/contrib/gdb-7/bfd/elf-ifunc.c @@ -125,11 +125,11 @@ _bfd_elf_create_ifunc_dyn_reloc (bfd *abfd, struct bfd_link_info *info, sreloc = _bfd_elf_make_dynamic_reloc_section (sec, htab->dynobj, bed->s->log_file_align, abfd, - bed->rela_plts_and_copies_p); + bed->rela_plts_and_copies_p); if (sreloc == NULL) return NULL; } - + p = *head; if (p == NULL || p->sec != sec) { @@ -175,7 +175,7 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, || info->export_dynamic) && h->pointer_equality_needed) { - info->callbacks->einfo + info->callbacks->einfo (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer " "equality in `%B' can not be used when making an " "executable; recompile with -fPIE and relink with -pie\n"), @@ -251,7 +251,7 @@ keep: } /* Don't update value of STT_GNU_IFUNC symbol to PLT. We need - the original value for R_*_IRELATIVE. */ + the original value for R_*_IRELATIVE. */ h->plt.offset = plt->size; /* Make room for this entry in the .plt/.iplt section. */ diff --git a/contrib/gdb-7/bfd/elf-linux-psinfo.h b/contrib/gdb-7/bfd/elf-linux-psinfo.h new file mode 100644 index 0000000000..c9652844ea --- /dev/null +++ b/contrib/gdb-7/bfd/elf-linux-psinfo.h @@ -0,0 +1,127 @@ +/* Definitions for PRPSINFO structures under ELF on GNU/Linux. + Copyright 2013 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef ELF_LINUX_PSINFO_H +#define ELF_LINUX_PSINFO_H + +/* The PRPSINFO structures defined below are used by most + architectures, although some of them define their own versions + (like e.g., PPC). */ + +/* External 32-bit structure for PRPSINFO. This structure is + ABI-defined, thus we choose to use char arrays here in order to + avoid dealing with different types in different architectures. + + This structure will ultimately be written in the corefile's note + section, as the PRPSINFO. */ + +struct elf_external_linux_prpsinfo32 + { + char pr_state; /* Numeric process state. */ + char pr_sname; /* Char for pr_state. */ + char pr_zomb; /* Zombie. */ + char pr_nice; /* Nice val. */ + char pr_flag[4]; /* Flags. */ + char pr_uid[2]; + char pr_gid[2]; + char pr_pid[4]; + char pr_ppid[4]; + char pr_pgrp[4]; + char pr_sid[4]; + char pr_fname[16]; /* Filename of executable. */ + char pr_psargs[80]; /* Initial part of arg list. */ + }; + +/* Helper macro to swap (properly handling endianess) things from the + `elf_internal_linux_prpsinfo' structure to the + `elf_external_linux_prpsinfo32' structure. + + Note that FROM should be a pointer, and TO should be the explicit + type. */ + +#define LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to) \ + do \ + { \ + H_PUT_8 (abfd, from->pr_state, &to.pr_state); \ + H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \ + H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \ + H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \ + H_PUT_32 (abfd, from->pr_flag, to.pr_flag); \ + H_PUT_16 (abfd, from->pr_uid, to.pr_uid); \ + H_PUT_16 (abfd, from->pr_gid, to.pr_gid); \ + H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \ + H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \ + H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \ + H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \ + strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \ + strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \ + } while (0) + +/* External 64-bit structure for PRPSINFO. This structure is + ABI-defined, thus we choose to use char arrays here in order to + avoid dealing with different types in different architectures. + + This structure will ultimately be written in the corefile's note + section, as the PRPSINFO. */ + +struct elf_external_linux_prpsinfo64 + { + char pr_state; /* Numeric process state. */ + char pr_sname; /* Char for pr_state. */ + char pr_zomb; /* Zombie. */ + char pr_nice; /* Nice val. */ + char pr_flag[8]; /* Flags. */ + char gap[4]; + char pr_uid[4]; + char pr_gid[4]; + char pr_pid[4]; + char pr_ppid[4]; + char pr_pgrp[4]; + char pr_sid[4]; + char pr_fname[16]; /* Filename of executable. */ + char pr_psargs[80]; /* Initial part of arg list. */ + }; + +/* Helper macro to swap (properly handling endianess) things from the + `elf_internal_linux_prpsinfo' structure to the + `elf_external_linux_prpsinfo64' structure. + + Note that FROM should be a pointer, and TO should be the explicit + type. */ + +#define LINUX_PRPSINFO64_SWAP_FIELDS(abfd, from, to) \ + do \ + { \ + H_PUT_8 (abfd, from->pr_state, &to.pr_state); \ + H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \ + H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \ + H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \ + H_PUT_64 (abfd, from->pr_flag, to.pr_flag); \ + H_PUT_32 (abfd, from->pr_uid, to.pr_uid); \ + H_PUT_32 (abfd, from->pr_gid, to.pr_gid); \ + H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \ + H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \ + H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \ + H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \ + strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \ + strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \ + } while (0) + +#endif diff --git a/contrib/gdb-7/bfd/elf-nacl.c b/contrib/gdb-7/bfd/elf-nacl.c new file mode 100644 index 0000000000..39ffb5d788 --- /dev/null +++ b/contrib/gdb-7/bfd/elf-nacl.c @@ -0,0 +1,224 @@ +/* Native Client support for ELF + Copyright 2012 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. */ + +#include "sysdep.h" +#include "bfd.h" +#include "elf-bfd.h" +#include "elf-nacl.h" +#include "elf/common.h" +#include "elf/internal.h" + +static bfd_boolean +segment_executable (struct elf_segment_map *seg) +{ + if (seg->p_flags_valid) + return (seg->p_flags & PF_X) != 0; + else + { + /* The p_flags value has not been computed yet, + so we have to look through the sections. */ + unsigned int i; + for (i = 0; i < seg->count; ++i) + if (seg->sections[i]->flags & SEC_CODE) + return TRUE; + } + return FALSE; +} + +/* Determine if this segment is eligible to receive the file and program + headers. It must be read-only, non-executable, and have contents. + Its first section must start far enough past the page boundary to + allow space for the headers. */ +static bfd_boolean +segment_eligible_for_headers (struct elf_segment_map *seg, + bfd_vma maxpagesize, bfd_vma sizeof_headers) +{ + bfd_boolean any_contents = FALSE; + unsigned int i; + if (seg->count == 0 || seg->sections[0]->lma % maxpagesize < sizeof_headers) + return FALSE; + for (i = 0; i < seg->count; ++i) + { + if ((seg->sections[i]->flags & (SEC_CODE|SEC_READONLY)) != SEC_READONLY) + return FALSE; + if (seg->sections[i]->flags & SEC_HAS_CONTENTS) + any_contents = TRUE; + } + return any_contents; +} + + +/* We permute the segment_map to get BFD to do the file layout we want: + The first non-executable PT_LOAD segment appears first in the file + and contains the ELF file header and phdrs. */ +bfd_boolean +nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info) +{ + struct elf_segment_map **m = &elf_seg_map (abfd); + struct elf_segment_map **first_load = NULL; + struct elf_segment_map **last_load = NULL; + bfd_boolean moved_headers = FALSE; + int sizeof_headers = info == NULL ? 0 : bfd_sizeof_headers (abfd, info); + bfd_vma maxpagesize = get_elf_backend_data (abfd)->maxpagesize; + + if (info != NULL && info->user_phdrs) + /* The linker script used PHDRS explicitly, so don't change what the + user asked for. */ + return TRUE; + + while (*m != NULL) + { + struct elf_segment_map *seg = *m; + + if (seg->p_type == PT_LOAD) + { + /* First, we're just finding the earliest PT_LOAD. + By the normal rules, this will be the lowest-addressed one. + We only have anything interesting to do if it's executable. */ + last_load = m; + if (first_load == NULL) + { + if (!segment_executable (*m)) + return TRUE; + first_load = m; + } + /* Now that we've noted the first PT_LOAD, we're looking for + the first non-executable PT_LOAD with a nonempty p_filesz. */ + else if (!moved_headers + && segment_eligible_for_headers (seg, maxpagesize, + sizeof_headers)) + { + /* This is the one we were looking for! + + First, clear the flags on previous segments that + say they include the file header and phdrs. */ + struct elf_segment_map *prevseg; + for (prevseg = *first_load; + prevseg != seg; + prevseg = prevseg->next) + if (prevseg->p_type == PT_LOAD) + { + prevseg->includes_filehdr = 0; + prevseg->includes_phdrs = 0; + } + + /* This segment will include those headers instead. */ + seg->includes_filehdr = 1; + seg->includes_phdrs = 1; + + moved_headers = TRUE; + } + } + + m = &seg->next; + } + + if (first_load != last_load && moved_headers) + { + /* Now swap the first and last PT_LOAD segments' + positions in segment_map. */ + struct elf_segment_map *first = *first_load; + struct elf_segment_map *last = *last_load; + *first_load = first->next; + first->next = last->next; + last->next = first; + } + + return TRUE; +} + +/* After nacl_modify_segment_map has done its work, the file layout has + been done as we wanted. But the PT_LOAD phdrs are no longer in the + proper order for the ELF rule that they must appear in ascending address + order. So find the two segments we swapped before, and swap them back. */ +bfd_boolean +nacl_modify_program_headers (bfd *abfd, struct bfd_link_info *info) +{ + struct elf_segment_map **m = &elf_seg_map (abfd); + Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; + Elf_Internal_Phdr *p = phdr; + + if (info != NULL && info->user_phdrs) + /* The linker script used PHDRS explicitly, so don't change what the + user asked for. */ + return TRUE; + + /* Find the PT_LOAD that contains the headers (should be the first). */ + while (*m != NULL) + { + if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr) + break; + + m = &(*m)->next; + ++p; + } + + if (*m != NULL) + { + struct elf_segment_map **first_load_seg = m; + Elf_Internal_Phdr *first_load_phdr = p; + struct elf_segment_map **next_load_seg = NULL; + Elf_Internal_Phdr *next_load_phdr = NULL; + + /* Now move past that first one and find the PT_LOAD that should be + before it by address order. */ + + m = &(*m)->next; + ++p; + + while ((*m) != NULL) + { + if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr) + { + next_load_seg = m; + next_load_phdr = p; + break; + } + + m = &(*m)->next; + ++p; + } + + /* Swap their positions in the segment_map back to how they used to be. + The phdrs have already been set up by now, so we have to slide up + the earlier ones to insert the one that should be first. */ + if (next_load_seg != NULL) + { + Elf_Internal_Phdr move_phdr; + struct elf_segment_map *first_seg = *first_load_seg; + struct elf_segment_map *next_seg = *next_load_seg; + struct elf_segment_map *first_next = first_seg->next; + struct elf_segment_map *next_next = next_seg->next; + + first_seg->next = next_next; + *first_load_seg = next_seg; + + next_seg->next = first_next; + *next_load_seg = first_seg; + + move_phdr = *next_load_phdr; + memmove (first_load_phdr + 1, first_load_phdr, + (next_load_phdr - first_load_phdr) * sizeof move_phdr); + *first_load_phdr = move_phdr; + } + } + + return TRUE; +} diff --git a/contrib/gdb-7/gdb/gdb_vfork.h b/contrib/gdb-7/bfd/elf-nacl.h similarity index 55% copy from contrib/gdb-7/gdb/gdb_vfork.h copy to contrib/gdb-7/bfd/elf-nacl.h index 736519db50..417c7e38e6 100644 --- a/contrib/gdb-7/gdb/gdb_vfork.h +++ b/contrib/gdb-7/bfd/elf-nacl.h @@ -1,7 +1,7 @@ -/* GDB-friendly replacement for . - Copyright (C) 2001, 2007-2012 Free Software Foundation, Inc. +/* Native Client support for ELF + Copyright 2012 Free Software Foundation, Inc. - This file is part of GDB. + This file is part of BFD, the Binary File Descriptor library. 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 @@ -14,13 +14,11 @@ 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 . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. */ -#ifndef GDB_VFORK_H -#define GDB_VFORK_H +#include "bfd.h" -#if HAVE_VFORK_H -#include -#endif - -#endif /* GDB_VFORK_H */ +bfd_boolean nacl_modify_segment_map (bfd *, struct bfd_link_info *); +bfd_boolean nacl_modify_program_headers (bfd *, struct bfd_link_info *); diff --git a/contrib/gdb-7/bfd/elf-strtab.c b/contrib/gdb-7/bfd/elf-strtab.c index 7d2fad4e51..61cedaedcc 100644 --- a/contrib/gdb-7/bfd/elf-strtab.c +++ b/contrib/gdb-7/bfd/elf-strtab.c @@ -201,15 +201,41 @@ _bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx) --tab->array[idx]->refcount; } +unsigned int +_bfd_elf_strtab_refcount (struct elf_strtab_hash *tab, bfd_size_type idx) +{ + return tab->array[idx]->refcount; +} + void _bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab) { bfd_size_type idx; - for (idx = 1; idx < tab->size; ++idx) + for (idx = 1; idx < tab->size; idx++) tab->array[idx]->refcount = 0; } +/* Downsizes strtab. Entries from IDX up to the current size are + removed from the array. */ +void +_bfd_elf_strtab_restore_size (struct elf_strtab_hash *tab, bfd_size_type idx) +{ + bfd_size_type curr_size = tab->size; + + BFD_ASSERT (tab->sec_size == 0); + BFD_ASSERT (idx <= curr_size); + tab->size = idx; + for (; idx < curr_size; ++idx) + { + /* We don't remove entries from the hash table, just set their + REFCOUNT to zero. Setting LEN zero will result in the size + growing if the entry is added again. See _bfd_elf_strtab_add. */ + tab->array[idx]->refcount = 0; + tab->array[idx]->len = 0; + } +} + bfd_size_type _bfd_elf_strtab_size (struct elf_strtab_hash *tab) { diff --git a/contrib/gdb-7/bfd/elf-vxworks.c b/contrib/gdb-7/bfd/elf-vxworks.c index 06edf8dce6..bb9dbbbafa 100644 --- a/contrib/gdb-7/bfd/elf-vxworks.c +++ b/contrib/gdb-7/bfd/elf-vxworks.c @@ -1,5 +1,5 @@ /* VxWorks support for ELF - Copyright 2005, 2006, 2007, 2009 Free Software Foundation, Inc. + Copyright 2005, 2006, 2007, 2009, 2012 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -91,12 +91,13 @@ elf_vxworks_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info, if (!info->shared) { - s = bfd_make_section_with_flags (dynobj, - bed->default_use_rela_p - ? ".rela.plt.unloaded" - : ".rel.plt.unloaded", - SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_READONLY | SEC_LINKER_CREATED); + s = bfd_make_section_anyway_with_flags (dynobj, + bed->default_use_rela_p + ? ".rela.plt.unloaded" + : ".rel.plt.unloaded", + SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_READONLY + | SEC_LINKER_CREATED); if (s == NULL || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) return FALSE; @@ -194,7 +195,7 @@ elf_vxworks_emit_relocs (bfd *output_bfd, { asection *sec = (*hash_ptr)->root.u.def.section; int this_idx = sec->output_section->target_index; - + irela[j].r_info = ELF32_R_INFO (this_idx, ELF32_R_TYPE (irela[j].r_info)); irela[j].r_addend += (*hash_ptr)->root.u.def.value; @@ -226,7 +227,7 @@ elf_vxworks_final_write_processing (bfd *abfd, if (!sec) return; d = elf_section_data (sec); - d->this_hdr.sh_link = elf_tdata (abfd)->symtab_section; + d->this_hdr.sh_link = elf_onesymtab (abfd); sec = bfd_get_section_by_name (abfd, ".plt"); if (sec) d->this_hdr.sh_info = elf_section_data (sec)->this_idx; @@ -261,33 +262,34 @@ bfd_boolean elf_vxworks_finish_dynamic_entry (bfd *output_bfd, Elf_Internal_Dyn *dyn) { asection *sec; - + switch (dyn->d_tag) { default: return FALSE; - + case DT_VX_WRS_TLS_DATA_START: sec = bfd_get_section_by_name (output_bfd, ".tls_data"); dyn->d_un.d_ptr = sec->vma; break; - + case DT_VX_WRS_TLS_DATA_SIZE: sec = bfd_get_section_by_name (output_bfd, ".tls_data"); dyn->d_un.d_val = sec->size; break; - + case DT_VX_WRS_TLS_DATA_ALIGN: sec = bfd_get_section_by_name (output_bfd, ".tls_data"); dyn->d_un.d_val - = (bfd_size_type)1 << bfd_get_section_alignment (abfd, sec); + = (bfd_size_type)1 << bfd_get_section_alignment (output_bfd, + sec); break; - + case DT_VX_WRS_TLS_VARS_START: sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); dyn->d_un.d_ptr = sec->vma; break; - + case DT_VX_WRS_TLS_VARS_SIZE: sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); dyn->d_un.d_val = sec->size; diff --git a/contrib/gdb-7/bfd/elf.c b/contrib/gdb-7/bfd/elf.c index f1e4882530..3ba7e5f11a 100644 --- a/contrib/gdb-7/bfd/elf.c +++ b/contrib/gdb-7/bfd/elf.c @@ -1,8 +1,6 @@ /* ELF executable support for BFD. - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright 1993-2013 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -44,6 +42,7 @@ SECTION #include "elf-bfd.h" #include "libiberty.h" #include "safe-ctype.h" +#include "elf-linux-psinfo.h" #ifdef CORE_HEADER #include CORE_HEADER @@ -244,7 +243,14 @@ bfd_elf_allocate_object (bfd *abfd, return FALSE; elf_object_id (abfd) = object_id; - elf_program_header_size (abfd) = (bfd_size_type) -1; + if (abfd->direction != read_direction) + { + struct output_elf_obj_tdata *o = bfd_zalloc (abfd, sizeof *o); + if (o == NULL) + return FALSE; + elf_tdata (abfd)->o = o; + elf_program_header_size (abfd) = (bfd_size_type) -1; + } return TRUE; } @@ -261,7 +267,10 @@ bfd_boolean bfd_elf_mkcorefile (bfd *abfd) { /* I think this can be done just like an object file. */ - return abfd->xvec->_bfd_set_format[(int) bfd_object] (abfd); + if (!abfd->xvec->_bfd_set_format[(int) bfd_object] (abfd)) + return FALSE; + elf_tdata (abfd)->core = bfd_zalloc (abfd, sizeof (*elf_tdata (abfd)->core)); + return elf_tdata (abfd)->core != NULL; } static char * @@ -545,9 +554,9 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) shnum = elf_numsections (abfd); num_group = 0; -#define IS_VALID_GROUP_SECTION_HEADER(shdr) \ +#define IS_VALID_GROUP_SECTION_HEADER(shdr, minsize) \ ( (shdr)->sh_type == SHT_GROUP \ - && (shdr)->sh_size >= (2 * GRP_ENTRY_SIZE) \ + && (shdr)->sh_size >= minsize \ && (shdr)->sh_entsize == GRP_ENTRY_SIZE \ && ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0) @@ -555,7 +564,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) { Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; - if (IS_VALID_GROUP_SECTION_HEADER (shdr)) + if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE)) num_group += 1; } @@ -581,7 +590,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) { Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; - if (IS_VALID_GROUP_SECTION_HEADER (shdr)) + if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE)) { unsigned char *src; Elf_Internal_Group *dest; @@ -880,45 +889,25 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, { /* The debugging sections appear to be recognized only by name, not any sort of flag. Their SEC_ALLOC bits are cleared. */ - static const struct - { - const char *name; - int len; - } debug_sections [] = - { - { STRING_COMMA_LEN ("debug") }, /* 'd' */ - { NULL, 0 }, /* 'e' */ - { NULL, 0 }, /* 'f' */ - { STRING_COMMA_LEN ("gnu.linkonce.wi.") }, /* 'g' */ - { NULL, 0 }, /* 'h' */ - { NULL, 0 }, /* 'i' */ - { NULL, 0 }, /* 'j' */ - { NULL, 0 }, /* 'k' */ - { STRING_COMMA_LEN ("line") }, /* 'l' */ - { NULL, 0 }, /* 'm' */ - { NULL, 0 }, /* 'n' */ - { NULL, 0 }, /* 'o' */ - { NULL, 0 }, /* 'p' */ - { NULL, 0 }, /* 'q' */ - { NULL, 0 }, /* 'r' */ - { STRING_COMMA_LEN ("stab") }, /* 's' */ - { NULL, 0 }, /* 't' */ - { NULL, 0 }, /* 'u' */ - { NULL, 0 }, /* 'v' */ - { NULL, 0 }, /* 'w' */ - { NULL, 0 }, /* 'x' */ - { NULL, 0 }, /* 'y' */ - { STRING_COMMA_LEN ("zdebug") } /* 'z' */ - }; - if (name [0] == '.') { - int i = name [1] - 'd'; - if (i >= 0 - && i < (int) ARRAY_SIZE (debug_sections) - && debug_sections [i].name != NULL - && strncmp (&name [1], debug_sections [i].name, - debug_sections [i].len) == 0) + const char *p; + int n; + if (name[1] == 'd') + p = ".debug", n = 6; + else if (name[1] == 'g' && name[2] == 'n') + p = ".gnu.linkonce.wi.", n = 17; + else if (name[1] == 'g' && name[2] == 'd') + p = ".gdb_index", n = 11; /* yes we really do mean 11. */ + else if (name[1] == 'l') + p = ".line", n = 5; + else if (name[1] == 's') + p = ".stab", n = 5; + else if (name[1] == 'z') + p = ".zdebug", n = 7; + else + p = NULL, n = 0; + if (p != NULL && strncmp (name, p, n) == 0) flags |= SEC_DEBUGGING; } } @@ -1025,7 +1014,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, else { /* Normal section. Check if we should compress. */ - if ((abfd->flags & BFD_COMPRESS)) + if ((abfd->flags & BFD_COMPRESS) && newsect->size != 0) action = compress; } @@ -1038,7 +1027,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, if (!bfd_init_section_compress_status (abfd, newsect)) { (*_bfd_error_handler) - (_("%B: unable to initialize commpress status for section %s"), + (_("%B: unable to initialize compress status for section %s"), abfd, name); return FALSE; } @@ -1058,7 +1047,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, if (!bfd_init_section_decompress_status (abfd, newsect)) { (*_bfd_error_handler) - (_("%B: unable to initialize decommpress status for section %s"), + (_("%B: unable to initialize decompress status for section %s"), abfd, name); return FALSE; } @@ -1454,9 +1443,9 @@ bfd_elf_print_symbol (bfd *abfd, bfd_fprintf_vma (abfd, file, val); /* If we have version information, print it. */ - if (elf_tdata (abfd)->dynversym_section != 0 - && (elf_tdata (abfd)->dynverdef_section != 0 - || elf_tdata (abfd)->dynverref_section != 0)) + if (elf_dynversym (abfd) != 0 + && (elf_dynverdef (abfd) != 0 + || elf_dynverref (abfd) != 0)) { unsigned int vernum; const char *version_string; @@ -1646,7 +1635,15 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (hdr->sh_entsize != bed->s->sizeof_sym) return FALSE; if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) - return FALSE; + { + if (hdr->sh_size != 0) + return FALSE; + /* Some assemblers erroneously set sh_info to one with a + zero sh_size. ld sees this as a global symbol count + of (unsigned) -1. Fix it here. */ + hdr->sh_info = 0; + return TRUE; + } BFD_ASSERT (elf_onesymtab (abfd) == 0); elf_onesymtab (abfd) = shindex; elf_tdata (abfd)->symtab_hdr = *hdr; @@ -1699,6 +1696,16 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (hdr->sh_entsize != bed->s->sizeof_sym) return FALSE; + if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) + { + if (hdr->sh_size != 0) + return FALSE; + /* Some linkers erroneously set sh_info to one with a + zero sh_size. ld sees this as a global symbol count + of (unsigned) -1. Fix it here. */ + hdr->sh_info = 0; + return TRUE; + } BFD_ASSERT (elf_dynsymtab (abfd) == 0); elf_dynsymtab (abfd) = shindex; elf_tdata (abfd)->dynsymtab_hdr = *hdr; @@ -1911,7 +1918,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) return TRUE; case SHT_GROUP: - if (! IS_VALID_GROUP_SECTION_HEADER (hdr)) + if (! IS_VALID_GROUP_SECTION_HEADER (hdr, GRP_ENTRY_SIZE)) return FALSE; if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) return FALSE; @@ -2063,6 +2070,9 @@ static const struct bfd_elf_special_section special_sections_d[] = { { STRING_COMMA_LEN (".data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, { STRING_COMMA_LEN (".data1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + /* There are more DWARF sections than these, but they needn't be added here + unless you have to cope with broken compilers that don't emit section + attributes or you want to help the user writing assembler. */ { STRING_COMMA_LEN (".debug"), 0, SHT_PROGBITS, 0 }, { STRING_COMMA_LEN (".debug_line"), 0, SHT_PROGBITS, 0 }, { STRING_COMMA_LEN (".debug_info"), 0, SHT_PROGBITS, 0 }, @@ -2527,7 +2537,7 @@ _bfd_elf_init_reloc_shdr (bfd *abfd, rel_hdr = bfd_zalloc (abfd, amt); reldata->hdr = rel_hdr; - amt = sizeof ".rela" + strlen (asect->name); + amt = sizeof ".rela" + strlen (asect->name); name = (char *) bfd_alloc (abfd, amt); if (name == NULL) return FALSE; @@ -2971,9 +2981,9 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) d->rela.idx = 0; } - t->shstrtab_section = section_number++; + elf_shstrtab_sec (abfd) = section_number++; _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name); - elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section; + elf_elfheader (abfd)->e_shstrndx = elf_shstrtab_sec (abfd); need_symtab = (bfd_get_symcount (abfd) > 0 || (link_info == NULL @@ -2981,21 +2991,28 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) == HAS_RELOC))); if (need_symtab) { - t->symtab_section = section_number++; + elf_onesymtab (abfd) = section_number++; _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name); if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF)) { - t->symtab_shndx_section = section_number++; + elf_symtab_shndx (abfd) = section_number++; t->symtab_shndx_hdr.sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), ".symtab_shndx", FALSE); if (t->symtab_shndx_hdr.sh_name == (unsigned int) -1) return FALSE; } - t->strtab_section = section_number++; + elf_strtab_sec (abfd) = section_number++; _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name); } + if (section_number >= SHN_LORESERVE) + { + _bfd_error_handler (_("%B: too many sections: %u"), + abfd, section_number); + return FALSE; + } + _bfd_elf_strtab_finalize (elf_shstrtab (abfd)); t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd)); @@ -3019,17 +3036,17 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) elf_elfsections (abfd) = i_shdrp; - i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr; + i_shdrp[elf_shstrtab_sec (abfd)] = &t->shstrtab_hdr; if (need_symtab) { - i_shdrp[t->symtab_section] = &t->symtab_hdr; + i_shdrp[elf_onesymtab (abfd)] = &t->symtab_hdr; if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF)) { - i_shdrp[t->symtab_shndx_section] = &t->symtab_shndx_hdr; - t->symtab_shndx_hdr.sh_link = t->symtab_section; + i_shdrp[elf_symtab_shndx (abfd)] = &t->symtab_shndx_hdr; + t->symtab_shndx_hdr.sh_link = elf_onesymtab (abfd); } - i_shdrp[t->strtab_section] = &t->strtab_hdr; - t->symtab_hdr.sh_link = t->strtab_section; + i_shdrp[elf_strtab_sec (abfd)] = &t->strtab_hdr; + t->symtab_hdr.sh_link = elf_strtab_sec (abfd); } for (sec = abfd->sections; sec; sec = sec->next) @@ -3052,12 +3069,12 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) the relocation entries apply. */ if (d->rel.idx != 0) { - d->rel.hdr->sh_link = t->symtab_section; + d->rel.hdr->sh_link = elf_onesymtab (abfd); d->rel.hdr->sh_info = d->this_idx; } if (d->rela.idx != 0) { - d->rela.hdr->sh_link = t->symtab_section; + d->rela.hdr->sh_link = elf_onesymtab (abfd); d->rela.hdr->sh_info = d->this_idx; } @@ -3071,7 +3088,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) if (link_info != NULL) { /* Check discarded linkonce section. */ - if (elf_discarded_section (s)) + if (discarded_section (s)) { asection *kept; (*_bfd_error_handler) @@ -3212,7 +3229,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) break; case SHT_GROUP: - d->this_hdr.sh_link = t->symtab_section; + d->this_hdr.sh_link = elf_onesymtab (abfd); } } @@ -3225,9 +3242,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) return TRUE; } -/* Map symbol from it's internal number to the external number, moving - all local symbols to be at the head of the list. */ - static bfd_boolean sym_is_global (bfd *abfd, asymbol *sym) { @@ -3242,19 +3256,31 @@ sym_is_global (bfd *abfd, asymbol *sym) } /* Don't output section symbols for sections that are not going to be - output. */ + output, that are duplicates or there is no BFD section. */ static bfd_boolean ignore_section_sym (bfd *abfd, asymbol *sym) { - return ((sym->flags & BSF_SECTION_SYM) != 0 - && !(sym->section->owner == abfd + elf_symbol_type *type_ptr; + + if ((sym->flags & BSF_SECTION_SYM) == 0) + return FALSE; + + type_ptr = elf_symbol_from (abfd, sym); + return ((type_ptr != NULL + && type_ptr->internal_elf_sym.st_shndx != 0 + && bfd_is_abs_section (sym->section)) + || !(sym->section->owner == abfd || (sym->section->output_section->owner == abfd - && sym->section->output_offset == 0))); + && sym->section->output_offset == 0) + || bfd_is_abs_section (sym->section))); } +/* Map symbol from it's internal number to the external number, moving + all local symbols to be at the head of the list. */ + static bfd_boolean -elf_map_symbols (bfd *abfd) +elf_map_symbols (bfd *abfd, unsigned int *pnum_locals) { unsigned int symcount = bfd_get_symcount (abfd); asymbol **syms = bfd_get_outsymbols (abfd); @@ -3294,7 +3320,8 @@ elf_map_symbols (bfd *abfd) if ((sym->flags & BSF_SECTION_SYM) != 0 && sym->value == 0 - && !ignore_section_sym (abfd, sym)) + && !ignore_section_sym (abfd, sym) + && !bfd_is_abs_section (sym->section)) { asection *sec = sym->section; @@ -3308,12 +3335,10 @@ elf_map_symbols (bfd *abfd) /* Classify all of the symbols. */ for (idx = 0; idx < symcount; idx++) { - if (ignore_section_sym (abfd, syms[idx])) - continue; - if (!sym_is_global (abfd, syms[idx])) - num_locals++; - else + if (sym_is_global (abfd, syms[idx])) num_globals++; + else if (!ignore_section_sym (abfd, syms[idx])) + num_locals++; } /* We will be adding a section symbol for each normal BFD section. Most @@ -3343,12 +3368,12 @@ elf_map_symbols (bfd *abfd) asymbol *sym = syms[idx]; unsigned int i; - if (ignore_section_sym (abfd, sym)) - continue; - if (!sym_is_global (abfd, sym)) + if (sym_is_global (abfd, sym)) + i = num_locals + num_globals2++; + else if (!ignore_section_sym (abfd, sym)) i = num_locals2++; else - i = num_locals + num_globals2++; + continue; new_syms[i] = sym; sym->udata.i = i + 1; } @@ -3371,8 +3396,7 @@ elf_map_symbols (bfd *abfd) bfd_set_symtab (abfd, new_syms, num_locals + num_globals); - elf_num_locals (abfd) = num_locals; - elf_num_globals (abfd) = num_globals; + *pnum_locals = num_locals; return TRUE; } @@ -3483,7 +3507,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, file_ptr off; Elf_Internal_Shdr *hdr; - off = elf_tdata (abfd)->next_file_pos; + off = elf_next_file_pos (abfd); hdr = &elf_tdata (abfd)->symtab_hdr; off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); @@ -3495,7 +3519,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, hdr = &elf_tdata (abfd)->strtab_hdr; off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); - elf_tdata (abfd)->next_file_pos = off; + elf_next_file_pos (abfd) = off; /* Now that we know where the .strtab section goes, write it out. */ @@ -3546,13 +3570,13 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info) ++segs; } - if (elf_tdata (abfd)->eh_frame_hdr) + if (elf_eh_frame_hdr (abfd)) { /* We need a PT_GNU_EH_FRAME segment. */ ++segs; } - if (elf_tdata (abfd)->stack_flags) + if (elf_stack_flags (abfd)) { /* We need a PT_GNU_STACK segment. */ ++segs; @@ -3614,8 +3638,7 @@ _bfd_elf_find_segment_containing_section (bfd * abfd, asection * section) struct elf_segment_map *m; Elf_Internal_Phdr *p; - for (m = elf_tdata (abfd)->segment_map, - p = elf_tdata (abfd)->phdr; + for (m = elf_seg_map (abfd), p = elf_tdata (abfd)->phdr; m != NULL; m = m->next, p++) { @@ -3699,7 +3722,7 @@ elf_modify_segment_map (bfd *abfd, sections from the segment map. We also remove excluded sections. Finally, any PT_LOAD segment without sections is removed. */ - m = &elf_tdata (abfd)->segment_map; + m = &elf_seg_map (abfd); while (*m) { unsigned int i, new_count; @@ -3743,7 +3766,11 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) const struct elf_backend_data *bed = get_elf_backend_data (abfd); bfd_boolean no_user_phdrs; - no_user_phdrs = elf_tdata (abfd)->segment_map == NULL; + no_user_phdrs = elf_seg_map (abfd) == NULL; + + if (info != NULL) + info->user_phdrs = !no_user_phdrs; + if (no_user_phdrs && bfd_count_sections (abfd) != 0) { asection *s; @@ -3850,10 +3877,11 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) program headers we will need. */ if (count > 0) { - bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size; + bfd_size_type phdr_size = elf_program_header_size (abfd); if (phdr_size == (bfd_size_type) -1) phdr_size = get_program_header_size (abfd, info); + phdr_size += bed->s->sizeof_ehdr; if ((abfd->flags & D_PAGED) == 0 || (sections[0]->lma & addr_mask) < phdr_size || ((sections[0]->lma & addr_mask) % maxpagesize @@ -4094,7 +4122,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME segment. */ - eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr; + eh_frame_hdr = elf_eh_frame_hdr (abfd); if (eh_frame_hdr != NULL && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0) { @@ -4111,7 +4139,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) pm = &m->next; } - if (elf_tdata (abfd)->stack_flags) + if (elf_stack_flags (abfd)) { amt = sizeof (struct elf_segment_map); m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); @@ -4119,8 +4147,15 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) goto error_return; m->next = NULL; m->p_type = PT_GNU_STACK; - m->p_flags = elf_tdata (abfd)->stack_flags; + m->p_flags = elf_stack_flags (abfd); + m->p_align = bed->stack_align; m->p_flags_valid = 1; + m->p_align_valid = m->p_align != 0; + if (info->stacksize > 0) + { + m->p_size = info->stacksize; + m->p_size_valid = 1; + } *pm = m; pm = &m->next; @@ -4130,18 +4165,25 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) { for (m = mfirst; m != NULL; m = m->next) { - if (m->p_type == PT_LOAD) + if (m->p_type == PT_LOAD + && m->count != 0 + && m->sections[0]->vma >= info->relro_start + && m->sections[0]->vma < info->relro_end) { - asection *last = m->sections[m->count - 1]; - bfd_vma vaddr = m->sections[0]->vma; - bfd_vma filesz = last->vma - vaddr + last->size; + i = m->count; + while (--i != (unsigned) -1) + if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) + == (SEC_LOAD | SEC_HAS_CONTENTS)) + break; - if (vaddr < info->relro_end - && vaddr >= info->relro_start - && (vaddr + filesz) >= info->relro_end) + if (i == (unsigned) -1) + continue; + + if (m->sections[i]->vma + m->sections[i]->size + >= info->relro_end) break; } - } + } /* Make a PT_GNU_RELRO segment only when it isn't empty. */ if (m != NULL) @@ -4161,15 +4203,15 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) } free (sections); - elf_tdata (abfd)->segment_map = mfirst; + elf_seg_map (abfd) = mfirst; } if (!elf_modify_segment_map (abfd, info, no_user_phdrs)) return FALSE; - for (count = 0, m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + for (count = 0, m = elf_seg_map (abfd); m != NULL; m = m->next) ++count; - elf_tdata (abfd)->program_header_size = count * bed->s->sizeof_phdr; + elf_program_header_size (abfd) = count * bed->s->sizeof_phdr; return TRUE; @@ -4333,7 +4375,7 @@ assign_file_positions_for_load_sections (bfd *abfd, return FALSE; alloc = 0; - for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + for (m = elf_seg_map (abfd); m != NULL; m = m->next) { ++alloc; if (m->header_size) @@ -4351,35 +4393,35 @@ assign_file_positions_for_load_sections (bfd *abfd, elf_elfheader (abfd)->e_phoff = 0; elf_elfheader (abfd)->e_phentsize = 0; } - + elf_elfheader (abfd)->e_phnum = alloc; - if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1) - elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr; + if (elf_program_header_size (abfd) == (bfd_size_type) -1) + elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr; else - BFD_ASSERT (elf_tdata (abfd)->program_header_size + BFD_ASSERT (elf_program_header_size (abfd) >= alloc * bed->s->sizeof_phdr); if (alloc == 0) { - elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr; + elf_next_file_pos (abfd) = bed->s->sizeof_ehdr; return TRUE; } - /* We're writing the size in elf_tdata (abfd)->program_header_size, + /* We're writing the size in elf_program_header_size (abfd), see assign_file_positions_except_relocs, so make sure we have that amount allocated, with trailing space cleared. - The variable alloc contains the computed need, while elf_tdata - (abfd)->program_header_size contains the size used for the + The variable alloc contains the computed need, while + elf_program_header_size (abfd) contains the size used for the layout. See ld/emultempl/elf-generic.em:gld${EMULATION_NAME}_map_segments where the layout is forced to according to a larger size in the last iterations for the testcase ld-elf/header. */ - BFD_ASSERT (elf_tdata (abfd)->program_header_size % bed->s->sizeof_phdr + BFD_ASSERT (elf_program_header_size (abfd) % bed->s->sizeof_phdr == 0); phdrs = (Elf_Internal_Phdr *) bfd_zalloc2 (abfd, - (elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr), + (elf_program_header_size (abfd) / bed->s->sizeof_phdr), sizeof (Elf_Internal_Phdr)); elf_tdata (abfd)->phdr = phdrs; if (phdrs == NULL) @@ -4397,7 +4439,7 @@ assign_file_positions_for_load_sections (bfd *abfd, header_pad -= off; off += header_pad; - for (m = elf_tdata (abfd)->segment_map, p = phdrs, j = 0; + for (m = elf_seg_map (abfd), p = phdrs, j = 0; m != NULL; m = m->next, p++, j++) { @@ -4546,8 +4588,6 @@ assign_file_positions_for_load_sections (bfd *abfd, p->p_memsz = bed->s->sizeof_ehdr; if (m->count > 0) { - BFD_ASSERT (p->p_type == PT_LOAD); - if (p->p_vaddr < (bfd_vma) off) { (*_bfd_error_handler) @@ -4574,7 +4614,6 @@ assign_file_positions_for_load_sections (bfd *abfd, if (m->count > 0) { - BFD_ASSERT (p->p_type == PT_LOAD); p->p_vaddr -= off - p->p_offset; if (!m->p_paddr_valid) p->p_paddr -= off - p->p_offset; @@ -4781,7 +4820,7 @@ assign_file_positions_for_load_sections (bfd *abfd, } } - elf_tdata (abfd)->next_file_pos = off; + elf_next_file_pos (abfd) = off; return TRUE; } @@ -4797,6 +4836,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd, Elf_Internal_Phdr *phdrs; Elf_Internal_Phdr *p; struct elf_segment_map *m; + struct elf_segment_map *hdrs_segment; bfd_vma filehdr_vaddr, filehdr_paddr; bfd_vma phdrs_vaddr, phdrs_paddr; file_ptr off; @@ -4806,10 +4846,9 @@ assign_file_positions_for_non_load_sections (bfd *abfd, i_shdrpp = elf_elfsections (abfd); num_sec = elf_numsections (abfd); - off = elf_tdata (abfd)->next_file_pos; + off = elf_next_file_pos (abfd); for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) { - struct elf_obj_tdata *tdata = elf_tdata (abfd); Elf_Internal_Shdr *hdr; hdr = *hdrpp; @@ -4820,12 +4859,13 @@ assign_file_positions_for_non_load_sections (bfd *abfd, BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos); else if ((hdr->sh_flags & SHF_ALLOC) != 0) { - (*_bfd_error_handler) - (_("%B: warning: allocated section `%s' not in segment"), - abfd, - (hdr->bfd_section == NULL - ? "*unknown*" - : hdr->bfd_section->name)); + if (hdr->sh_size != 0) + (*_bfd_error_handler) + (_("%B: warning: allocated section `%s' not in segment"), + abfd, + (hdr->bfd_section == NULL + ? "*unknown*" + : hdr->bfd_section->name)); /* We don't need to page align empty sections. */ if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0) off += vma_page_aligned_bias (hdr->sh_addr, off, @@ -4838,9 +4878,9 @@ assign_file_positions_for_non_load_sections (bfd *abfd, } else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) && hdr->bfd_section == NULL) - || hdr == i_shdrpp[tdata->symtab_section] - || hdr == i_shdrpp[tdata->symtab_shndx_section] - || hdr == i_shdrpp[tdata->strtab_section]) + || hdr == i_shdrpp[elf_onesymtab (abfd)] + || hdr == i_shdrpp[elf_symtab_shndx (abfd)] + || hdr == i_shdrpp[elf_strtab_sec (abfd)]) hdr->sh_offset = -1; else off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); @@ -4853,10 +4893,9 @@ assign_file_positions_for_non_load_sections (bfd *abfd, filehdr_paddr = 0; phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; phdrs_paddr = 0; + hdrs_segment = NULL; phdrs = elf_tdata (abfd)->phdr; - for (m = elf_tdata (abfd)->segment_map, p = phdrs; - m != NULL; - m = m->next, p++) + for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++) { ++count; if (p->p_type != PT_LOAD) @@ -4873,34 +4912,85 @@ assign_file_positions_for_non_load_sections (bfd *abfd, phdrs_paddr = p->p_paddr; if (m->includes_filehdr) { + hdrs_segment = m; phdrs_vaddr += bed->s->sizeof_ehdr; phdrs_paddr += bed->s->sizeof_ehdr; } } } - for (m = elf_tdata (abfd)->segment_map, p = phdrs; - m != NULL; - m = m->next, p++) + if (hdrs_segment != NULL && link_info != NULL) + { + /* There is a segment that contains both the file headers and the + program headers, so provide a symbol __ehdr_start pointing there. + A program can use this to examine itself robustly. */ + + struct elf_link_hash_entry *hash + = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start", + FALSE, FALSE, TRUE); + /* If the symbol was referenced and not defined, define it. */ + if (hash != NULL + && (hash->root.type == bfd_link_hash_new + || hash->root.type == bfd_link_hash_undefined + || hash->root.type == bfd_link_hash_undefweak + || hash->root.type == bfd_link_hash_common)) + { + asection *s = NULL; + if (hdrs_segment->count != 0) + /* The segment contains sections, so use the first one. */ + s = hdrs_segment->sections[0]; + else + /* Use the first (i.e. lowest-addressed) section in any segment. */ + for (m = elf_seg_map (abfd); m != NULL; m = m->next) + if (m->count != 0) + { + s = m->sections[0]; + break; + } + + if (s != NULL) + { + hash->root.u.def.value = filehdr_vaddr - s->vma; + hash->root.u.def.section = s; + } + else + { + hash->root.u.def.value = filehdr_vaddr; + hash->root.u.def.section = bfd_abs_section_ptr; + } + + hash->root.type = bfd_link_hash_defined; + hash->def_regular = 1; + hash->non_elf = 0; + } + } + + for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++) { if (p->p_type == PT_GNU_RELRO) { const Elf_Internal_Phdr *lp; - - BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs); + struct elf_segment_map *lm; if (link_info != NULL) { /* During linking the range of the RELRO segment is passed in link_info. */ - for (lp = phdrs; lp < phdrs + count; ++lp) + for (lm = elf_seg_map (abfd), lp = phdrs; + lm != NULL; + lm = lm->next, lp++) { if (lp->p_type == PT_LOAD - && lp->p_vaddr >= link_info->relro_start && lp->p_vaddr < link_info->relro_end - && lp->p_vaddr + lp->p_filesz >= link_info->relro_end) + && lp->p_vaddr + lp->p_filesz >= link_info->relro_end + && lm->count != 0 + && lm->sections[0]->vma >= link_info->relro_start) break; } + + /* PR ld/14207. If the RELRO segment doesn't fit in the + LOAD segment, it should be removed. */ + BFD_ASSERT (lm != NULL); } else { @@ -4926,8 +5016,15 @@ assign_file_positions_for_non_load_sections (bfd *abfd, else abort (); p->p_memsz = p->p_filesz; - p->p_align = 1; - p->p_flags = (lp->p_flags & ~PF_W); + /* Preserve the alignment and flags if they are valid. The + gold linker generates RW/4 for the PT_GNU_RELRO section. + It is better for objcopy/strip to honor these attributes + otherwise gdb will choke when using separate debug files. + */ + if (!m->p_align_valid) + p->p_align = 1; + if (!m->p_flags_valid) + p->p_flags = (lp->p_flags & ~PF_W); } else { @@ -4935,6 +5032,11 @@ assign_file_positions_for_non_load_sections (bfd *abfd, p->p_type = PT_NULL; } } + else if (p->p_type == PT_GNU_STACK) + { + if (m->p_size_valid) + p->p_memsz = m->p_size; + } else if (m->count != 0) { if (p->p_type != PT_LOAD @@ -4972,7 +5074,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd, } } - elf_tdata (abfd)->next_file_pos = off; + elf_next_file_pos (abfd) = off; return TRUE; } @@ -5021,9 +5123,9 @@ assign_file_positions_except_relocs (bfd *abfd, hdr = *hdrpp; if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) && hdr->bfd_section == NULL) - || i == tdata->symtab_section - || i == tdata->symtab_shndx_section - || i == tdata->strtab_section) + || i == elf_onesymtab (abfd) + || i == elf_symtab_shndx (abfd) + || i == elf_strtab_sec (abfd)) { hdr->sh_offset = -1; } @@ -5051,12 +5153,12 @@ assign_file_positions_except_relocs (bfd *abfd, } /* Write out the program headers. */ - alloc = tdata->program_header_size / bed->s->sizeof_phdr; + alloc = elf_program_header_size (abfd) / bed->s->sizeof_phdr; if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0) return FALSE; - off = tdata->next_file_pos; + off = elf_next_file_pos (abfd); } /* Place the section headers. */ @@ -5064,7 +5166,7 @@ assign_file_positions_except_relocs (bfd *abfd, i_ehdrp->e_shoff = off; off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; - tdata->next_file_pos = off; + elf_next_file_pos (abfd) = off; return TRUE; } @@ -5167,7 +5269,7 @@ _bfd_elf_assign_file_positions_for_relocs (bfd *abfd) unsigned int i, num_sec; Elf_Internal_Shdr **shdrpp; - off = elf_tdata (abfd)->next_file_pos; + off = elf_next_file_pos (abfd); num_sec = elf_numsections (abfd); for (i = 1, shdrpp = elf_elfsections (abfd) + 1; i < num_sec; i++, shdrpp++) @@ -5180,7 +5282,7 @@ _bfd_elf_assign_file_positions_for_relocs (bfd *abfd) off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE); } - elf_tdata (abfd)->next_file_pos = off; + elf_next_file_pos (abfd) = off; } bfd_boolean @@ -5190,6 +5292,7 @@ _bfd_elf_write_object_contents (bfd *abfd) Elf_Internal_Shdr **i_shdrp; bfd_boolean failed; unsigned int count, num_sec; + struct elf_obj_tdata *t; if (! abfd->output_has_begun && ! _bfd_elf_compute_section_file_positions (abfd, NULL)) @@ -5221,21 +5324,21 @@ _bfd_elf_write_object_contents (bfd *abfd) } /* Write out the section header names. */ + t = elf_tdata (abfd); if (elf_shstrtab (abfd) != NULL - && (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0 + && (bfd_seek (abfd, t->shstrtab_hdr.sh_offset, SEEK_SET) != 0 || !_bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))) return FALSE; if (bed->elf_backend_final_write_processing) - (*bed->elf_backend_final_write_processing) (abfd, - elf_tdata (abfd)->linker); + (*bed->elf_backend_final_write_processing) (abfd, elf_linker (abfd)); if (!bed->s->write_shdrs_and_ehdr (abfd)) return FALSE; /* This is last since write_shdrs_and_ehdr can touch i_shdrp[0]. */ - if (elf_tdata (abfd)->after_write_object_contents) - return (*elf_tdata (abfd)->after_write_object_contents) (abfd); + if (t->o->build_id.after_write_object_contents != NULL) + return (*t->o->build_id.after_write_object_contents) (abfd); return TRUE; } @@ -5427,7 +5530,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) 1. It is within the address space of the segment -- we use the LMA if that is set for the segment and the VMA otherwise, 2. It is an allocated section or a NOTE section in a PT_NOTE - segment. + segment. 3. There is an output section associated with it, 4. The section has not already been allocated to a previous segment. 5. PT_GNU_STACK segments do not include any sections. @@ -5944,7 +6047,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) and carry on looping. */ amt = sizeof (struct elf_segment_map); amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); - map = (struct elf_segment_map *) bfd_alloc (obfd, amt); + map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); if (map == NULL) { free (sections); @@ -5969,7 +6072,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) free (sections); } - elf_tdata (obfd)->segment_map = map_first; + elf_seg_map (obfd) = map_first; /* If we had to estimate the number of program headers that were going to be needed, then check our estimate now and adjust @@ -6079,12 +6182,15 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) map->p_align_valid = 1; map->p_vaddr_offset = 0; - if (map->p_type == PT_GNU_RELRO) + if (map->p_type == PT_GNU_RELRO + || map->p_type == PT_GNU_STACK) { /* The PT_GNU_RELRO segment may contain the first a few bytes in the .got.plt section even if the whole .got.plt section isn't in the PT_GNU_RELRO segment. We won't - change the size of the PT_GNU_RELRO segment. */ + change the size of the PT_GNU_RELRO segment. + Similarly, PT_GNU_STACK size is significant on uclinux + systems. */ map->p_size = segment->p_memsz; map->p_size_valid = 1; } @@ -6147,7 +6253,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) if (map->includes_filehdr && lowest_section != NULL) /* We need to keep the space used by the headers fixed. */ map->header_size = lowest_section->vma - segment->p_vaddr; - + if (!map->includes_phdrs && !map->includes_filehdr && map->p_paddr_valid) @@ -6160,7 +6266,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) pointer_to_map = &map->next; } - elf_tdata (obfd)->segment_map = map_first; + elf_seg_map (obfd) = map_first; return TRUE; } @@ -6254,6 +6360,26 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) } rewrite: + if (ibfd->xvec == obfd->xvec) + { + /* When rewriting program header, set the output maxpagesize to + the maximum alignment of input PT_LOAD segments. */ + Elf_Internal_Phdr *segment; + unsigned int i; + unsigned int num_segments = elf_elfheader (ibfd)->e_phnum; + bfd_vma maxpagesize = 0; + + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + if (segment->p_type == PT_LOAD + && maxpagesize < segment->p_align) + maxpagesize = segment->p_align; + + if (maxpagesize != get_elf_backend_data (obfd)->maxpagesize) + bfd_emul_set_maxpagesize (bfd_get_target (obfd), maxpagesize); + } + return rewrite_elf_program_header (ibfd, obfd); } @@ -6431,7 +6557,7 @@ _bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) entry point, because the latter is called after the section contents have been set, which means that the program headers have already been worked out. */ - if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL) + if (elf_seg_map (obfd) == NULL && elf_tdata (ibfd)->phdr != NULL) { if (! copy_private_bfd_data (ibfd, obfd)) return FALSE; @@ -6479,11 +6605,11 @@ _bfd_elf_copy_private_symbol_data (bfd *ibfd, shndx = MAP_ONESYMTAB; else if (shndx == elf_dynsymtab (ibfd)) shndx = MAP_DYNSYMTAB; - else if (shndx == elf_tdata (ibfd)->strtab_section) + else if (shndx == elf_strtab_sec (ibfd)) shndx = MAP_STRTAB; - else if (shndx == elf_tdata (ibfd)->shstrtab_section) + else if (shndx == elf_shstrtab_sec (ibfd)) shndx = MAP_SHSTRTAB; - else if (shndx == elf_tdata (ibfd)->symtab_shndx_section) + else if (shndx == elf_symtab_shndx (ibfd)) shndx = MAP_SYM_SHNDX; osym->internal_elf_sym.st_shndx = shndx; } @@ -6508,10 +6634,11 @@ swap_out_syms (bfd *abfd, bfd_byte *outbound_syms; bfd_byte *outbound_shndx; int idx; + unsigned int num_locals; bfd_size_type amt; bfd_boolean name_local_sections; - if (!elf_map_symbols (abfd)) + if (!elf_map_symbols (abfd, &num_locals)) return FALSE; /* Dump out the symtabs. */ @@ -6525,7 +6652,7 @@ swap_out_syms (bfd *abfd, symtab_hdr->sh_type = SHT_SYMTAB; symtab_hdr->sh_entsize = bed->s->sizeof_sym; symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1); - symtab_hdr->sh_info = elf_num_locals (abfd) + 1; + symtab_hdr->sh_info = num_locals + 1; symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align; symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; @@ -6659,15 +6786,16 @@ swap_out_syms (bfd *abfd, shndx = elf_dynsymtab (abfd); break; case MAP_STRTAB: - shndx = elf_tdata (abfd)->strtab_section; + shndx = elf_strtab_sec (abfd); break; case MAP_SHSTRTAB: - shndx = elf_tdata (abfd)->shstrtab_section; + shndx = elf_shstrtab_sec (abfd); break; case MAP_SYM_SHNDX: - shndx = elf_tdata (abfd)->symtab_shndx_section; + shndx = elf_symtab_shndx (abfd); break; default: + shndx = SHN_ABS; break; } } @@ -7260,7 +7388,7 @@ error_return_verdef: Elf_Internal_Verdef *iverdef; Elf_Internal_Verdaux *iverdaux; - iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];; + iverdef = &elf_tdata (abfd)->verdef[freeidx - 1]; iverdef->vd_version = VER_DEF_CURRENT; iverdef->vd_flags = 0; @@ -7378,74 +7506,94 @@ elf_find_function (bfd *abfd, const char **filename_ptr, const char **functionname_ptr) { - const char *filename; - asymbol *func, *file; - bfd_vma low_func; - asymbol **p; - /* ??? Given multiple file symbols, it is impossible to reliably - choose the right file name for global symbols. File symbols are - local symbols, and thus all file symbols must sort before any - global symbols. The ELF spec may be interpreted to say that a - file symbol must sort before other local symbols, but currently - ld -r doesn't do this. So, for ld -r output, it is possible to - make a better choice of file name for local symbols by ignoring - file symbols appearing after a given local symbol. */ - enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_find_function_cache + { + asection *last_section; + asymbol *func; + const char *filename; + bfd_size_type func_size; + } *cache; if (symbols == NULL) return FALSE; - filename = NULL; - func = NULL; - file = NULL; - low_func = 0; - state = nothing_seen; - - for (p = symbols; *p != NULL; p++) + cache = elf_tdata (abfd)->elf_find_function_cache; + if (cache == NULL) { - elf_symbol_type *q; - unsigned int type; - - q = (elf_symbol_type *) *p; + cache = bfd_zalloc (abfd, sizeof (*cache)); + elf_tdata (abfd)->elf_find_function_cache = cache; + if (cache == NULL) + return FALSE; + } + if (cache->last_section != section + || cache->func == NULL + || offset < cache->func->value + || offset >= cache->func->value + cache->func_size) + { + asymbol *file; + bfd_vma low_func; + asymbol **p; + /* ??? Given multiple file symbols, it is impossible to reliably + choose the right file name for global symbols. File symbols are + local symbols, and thus all file symbols must sort before any + global symbols. The ELF spec may be interpreted to say that a + file symbol must sort before other local symbols, but currently + ld -r doesn't do this. So, for ld -r output, it is possible to + make a better choice of file name for local symbols by ignoring + file symbols appearing after a given local symbol. */ + enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + file = NULL; + low_func = 0; + state = nothing_seen; + cache->filename = NULL; + cache->func = NULL; + cache->func_size = 0; + cache->last_section = section; + + for (p = symbols; *p != NULL; p++) + { + asymbol *sym = *p; + bfd_vma code_off; + bfd_size_type size; + + if ((sym->flags & BSF_FILE) != 0) + { + file = sym; + if (state == symbol_seen) + state = file_after_symbol_seen; + continue; + } - type = ELF_ST_TYPE (q->internal_elf_sym.st_info); - switch (type) - { - case STT_FILE: - file = &q->symbol; - if (state == symbol_seen) - state = file_after_symbol_seen; - continue; - default: - if (!bed->is_function_type (type)) - break; - case STT_NOTYPE: - if (bfd_get_section (&q->symbol) == section - && q->symbol.value >= low_func - && q->symbol.value <= offset) + size = bed->maybe_function_sym (sym, section, &code_off); + if (size != 0 + && code_off <= offset + && (code_off > low_func + || (code_off == low_func + && size > cache->func_size))) { - func = (asymbol *) q; - low_func = q->symbol.value; - filename = NULL; + cache->func = sym; + cache->func_size = size; + cache->filename = NULL; + low_func = code_off; if (file != NULL - && (ELF_ST_BIND (q->internal_elf_sym.st_info) == STB_LOCAL + && ((sym->flags & BSF_LOCAL) != 0 || state != file_after_symbol_seen)) - filename = bfd_asymbol_name (file); + cache->filename = bfd_asymbol_name (file); } - break; + if (state == nothing_seen) + state = symbol_seen; } - if (state == nothing_seen) - state = symbol_seen; } - if (func == NULL) + if (cache->func == NULL) return FALSE; if (filename_ptr) - *filename_ptr = filename; + *filename_ptr = cache->filename; if (functionname_ptr) - *functionname_ptr = bfd_asymbol_name (func); + *functionname_ptr = bfd_asymbol_name (cache->func); return TRUE; } @@ -7461,6 +7609,23 @@ _bfd_elf_find_nearest_line (bfd *abfd, const char **filename_ptr, const char **functionname_ptr, unsigned int *line_ptr) +{ + return _bfd_elf_find_nearest_line_discriminator (abfd, section, symbols, + offset, filename_ptr, + functionname_ptr, + line_ptr, + NULL); +} + +bfd_boolean +_bfd_elf_find_nearest_line_discriminator (bfd *abfd, + asection *section, + asymbol **symbols, + bfd_vma offset, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *line_ptr, + unsigned int *discriminator_ptr) { bfd_boolean found; @@ -7479,7 +7644,7 @@ _bfd_elf_find_nearest_line (bfd *abfd, if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections, section, symbols, offset, filename_ptr, functionname_ptr, - line_ptr, 0, + line_ptr, discriminator_ptr, 0, &elf_tdata (abfd)->dwarf2_find_line_info)) { if (!*functionname_ptr) @@ -7514,9 +7679,20 @@ _bfd_elf_find_nearest_line (bfd *abfd, bfd_boolean _bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol, const char **filename_ptr, unsigned int *line_ptr) +{ + return _bfd_elf_find_line_discriminator (abfd, symbols, symbol, + filename_ptr, line_ptr, + NULL); +} + +bfd_boolean +_bfd_elf_find_line_discriminator (bfd *abfd, asymbol **symbols, asymbol *symbol, + const char **filename_ptr, + unsigned int *line_ptr, + unsigned int *discriminator_ptr) { return _bfd_dwarf2_find_line (abfd, symbols, symbol, - filename_ptr, line_ptr, 0, + filename_ptr, line_ptr, discriminator_ptr, 0, &elf_tdata (abfd)->dwarf2_find_line_info); } @@ -7547,21 +7723,21 @@ _bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info) if (!info->relocatable) { - bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size; + bfd_size_type phdr_size = elf_program_header_size (abfd); if (phdr_size == (bfd_size_type) -1) { struct elf_segment_map *m; phdr_size = 0; - for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + for (m = elf_seg_map (abfd); m != NULL; m = m->next) phdr_size += bed->s->sizeof_phdr; if (phdr_size == 0) phdr_size = get_program_header_size (abfd, info); } - elf_tdata (abfd)->program_header_size = phdr_size; + elf_program_header_size (abfd) = phdr_size; ret += phdr_size; } @@ -7698,11 +7874,12 @@ _bfd_elf_validate_reloc (bfd *abfd, arelent *areloc) bfd_boolean _bfd_elf_close_and_cleanup (bfd *abfd) { - if (bfd_get_format (abfd) == bfd_object) + struct elf_obj_tdata *tdata = elf_tdata (abfd); + if (bfd_get_format (abfd) == bfd_object && tdata != NULL) { - if (elf_tdata (abfd) != NULL && elf_shstrtab (abfd) != NULL) + if (elf_tdata (abfd)->o != NULL && elf_shstrtab (abfd) != NULL) _bfd_elf_strtab_free (elf_shstrtab (abfd)); - _bfd_dwarf2_cleanup_debug_info (abfd); + _bfd_dwarf2_cleanup_debug_info (abfd, &tdata->dwarf2_find_line_info); } return _bfd_generic_close_and_cleanup (abfd); @@ -7742,9 +7919,9 @@ elfcore_make_pid (bfd *abfd) { int pid; - pid = elf_tdata (abfd)->core_lwpid; + pid = elf_tdata (abfd)->core->lwpid; if (pid == 0) - pid = elf_tdata (abfd)->core_pid; + pid = elf_tdata (abfd)->core->pid; return pid; } @@ -7834,10 +8011,10 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) /* Do not overwrite the core signal if it has already been set by another thread. */ - if (elf_tdata (abfd)->core_signal == 0) - elf_tdata (abfd)->core_signal = prstat.pr_cursig; - if (elf_tdata (abfd)->core_pid == 0) - elf_tdata (abfd)->core_pid = prstat.pr_pid; + if (elf_tdata (abfd)->core->signal == 0) + elf_tdata (abfd)->core->signal = prstat.pr_cursig; + if (elf_tdata (abfd)->core->pid == 0) + elf_tdata (abfd)->core->pid = prstat.pr_pid; /* pr_who exists on: solaris 2.5+ @@ -7846,9 +8023,9 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) linux 2.[01] */ #if defined (HAVE_PRSTATUS_T_PR_WHO) - elf_tdata (abfd)->core_lwpid = prstat.pr_who; + elf_tdata (abfd)->core->lwpid = prstat.pr_who; #else - elf_tdata (abfd)->core_lwpid = prstat.pr_pid; + elf_tdata (abfd)->core->lwpid = prstat.pr_pid; #endif } #if defined (HAVE_PRSTATUS32_T) @@ -7863,10 +8040,10 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) /* Do not overwrite the core signal if it has already been set by another thread. */ - if (elf_tdata (abfd)->core_signal == 0) - elf_tdata (abfd)->core_signal = prstat.pr_cursig; - if (elf_tdata (abfd)->core_pid == 0) - elf_tdata (abfd)->core_pid = prstat.pr_pid; + if (elf_tdata (abfd)->core->signal == 0) + elf_tdata (abfd)->core->signal = prstat.pr_cursig; + if (elf_tdata (abfd)->core->pid == 0) + elf_tdata (abfd)->core->pid = prstat.pr_pid; /* pr_who exists on: solaris 2.5+ @@ -7875,9 +8052,9 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) linux 2.[01] */ #if defined (HAVE_PRSTATUS32_T_PR_WHO) - elf_tdata (abfd)->core_lwpid = prstat.pr_who; + elf_tdata (abfd)->core->lwpid = prstat.pr_who; #else - elf_tdata (abfd)->core_lwpid = prstat.pr_pid; + elf_tdata (abfd)->core->lwpid = prstat.pr_pid; #endif } #endif /* HAVE_PRSTATUS32_T */ @@ -7994,12 +8171,36 @@ elfcore_grok_s390_system_call (bfd *abfd, Elf_Internal_Note *note) return elfcore_make_note_pseudosection (abfd, ".reg-s390-system-call", note); } +static bfd_boolean +elfcore_grok_s390_tdb (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-tdb", note); +} + static bfd_boolean elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note) { return elfcore_make_note_pseudosection (abfd, ".reg-arm-vfp", note); } +static bfd_boolean +elfcore_grok_aarch_tls (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-aarch-tls", note); +} + +static bfd_boolean +elfcore_grok_aarch_hw_break (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-break", note); +} + +static bfd_boolean +elfcore_grok_aarch_hw_watch (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-watch", note); +} + #if defined (HAVE_PRPSINFO_T) typedef prpsinfo_t elfcore_psinfo_t; #if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */ @@ -8051,13 +8252,13 @@ elfcore_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) memcpy (&psinfo, note->descdata, sizeof (psinfo)); #if defined (HAVE_PSINFO_T_PR_PID) || defined (HAVE_PRPSINFO_T_PR_PID) - elf_tdata (abfd)->core_pid = psinfo.pr_pid; + elf_tdata (abfd)->core->pid = psinfo.pr_pid; #endif - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, psinfo.pr_fname, sizeof (psinfo.pr_fname)); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, psinfo.pr_psargs, sizeof (psinfo.pr_psargs)); } @@ -8070,13 +8271,13 @@ elfcore_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) memcpy (&psinfo, note->descdata, sizeof (psinfo)); #if defined (HAVE_PSINFO32_T_PR_PID) || defined (HAVE_PRPSINFO32_T_PR_PID) - elf_tdata (abfd)->core_pid = psinfo.pr_pid; + elf_tdata (abfd)->core->pid = psinfo.pr_pid; #endif - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, psinfo.pr_fname, sizeof (psinfo.pr_fname)); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, psinfo.pr_psargs, sizeof (psinfo.pr_psargs)); } @@ -8094,7 +8295,7 @@ elfcore_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) implementations, so strip it off if it exists. */ { - char *command = elf_tdata (abfd)->core_command; + char *command = elf_tdata (abfd)->core->command; int n = strlen (command); if (0 < n && command[n - 1] == ' ') @@ -8119,7 +8320,7 @@ elfcore_grok_pstatus (bfd *abfd, Elf_Internal_Note *note) memcpy (&pstat, note->descdata, sizeof (pstat)); - elf_tdata (abfd)->core_pid = pstat.pr_pid; + elf_tdata (abfd)->core->pid = pstat.pr_pid; } #if defined (HAVE_PSTATUS32_T) else if (note->descsz == sizeof (pstatus32_t)) @@ -8129,7 +8330,7 @@ elfcore_grok_pstatus (bfd *abfd, Elf_Internal_Note *note) memcpy (&pstat, note->descdata, sizeof (pstat)); - elf_tdata (abfd)->core_pid = pstat.pr_pid; + elf_tdata (abfd)->core->pid = pstat.pr_pid; } #endif /* Could grab some more details from the "representative" @@ -8159,11 +8360,11 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) memcpy (&lwpstat, note->descdata, sizeof (lwpstat)); - elf_tdata (abfd)->core_lwpid = lwpstat.pr_lwpid; + elf_tdata (abfd)->core->lwpid = lwpstat.pr_lwpid; /* Do not overwrite the core signal if it has already been set by another thread. */ - if (elf_tdata (abfd)->core_signal == 0) - elf_tdata (abfd)->core_signal = lwpstat.pr_cursig; + if (elf_tdata (abfd)->core->signal == 0) + elf_tdata (abfd)->core->signal = lwpstat.pr_cursig; /* Make a ".reg/999" section. */ @@ -8246,11 +8447,11 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) switch (type) { case 1 /* NOTE_INFO_PROCESS */: - /* FIXME: need to add ->core_command. */ + /* FIXME: need to add ->core->command. */ /* process_info.pid */ - elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 8); + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 8); /* process_info.signal */ - elf_tdata (abfd)->core_signal = bfd_get_32 (abfd, note->descdata + 12); + elf_tdata (abfd)->core->signal = bfd_get_32 (abfd, note->descdata + 12); break; case 2 /* NOTE_INFO_THREAD */: @@ -8433,6 +8634,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) else return TRUE; + case NT_S390_TDB: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_tdb (abfd, note); + else + return TRUE; + case NT_ARM_VFP: if (note->namesz == 6 && strcmp (note->namedata, "LINUX") == 0) @@ -8440,6 +8648,27 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) else return TRUE; + case NT_ARM_TLS: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_aarch_tls (abfd, note); + else + return TRUE; + + case NT_ARM_HW_BREAK: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_aarch_hw_break (abfd, note); + else + return TRUE; + + case NT_ARM_HW_WATCH: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_aarch_hw_watch (abfd, note); + else + return TRUE; + case NT_PRPSINFO: case NT_PSINFO: if (bed->elf_backend_grok_psinfo) @@ -8464,18 +8693,32 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) return TRUE; } + + case NT_FILE: + return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.file", + note); + + case NT_SIGINFO: + return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo", + note); } } static bfd_boolean elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note) { - elf_tdata (abfd)->build_id_size = note->descsz; - elf_tdata (abfd)->build_id = (bfd_byte *) bfd_alloc (abfd, note->descsz); - if (elf_tdata (abfd)->build_id == NULL) + struct elf_obj_tdata *t; + + if (note->descsz == 0) + return FALSE; + + t = elf_tdata (abfd); + t->build_id = bfd_alloc (abfd, sizeof (*t->build_id) - 1 + note->descsz); + if (t->build_id == NULL) return FALSE; - memcpy (elf_tdata (abfd)->build_id, note->descdata, note->descsz); + t->build_id->size = note->descsz; + memcpy (t->build_id->data, note->descdata, note->descsz); return TRUE; } @@ -8540,15 +8783,15 @@ static bfd_boolean elfcore_grok_netbsd_procinfo (bfd *abfd, Elf_Internal_Note *note) { /* Signal number at offset 0x08. */ - elf_tdata (abfd)->core_signal + elf_tdata (abfd)->core->signal = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08); /* Process ID at offset 0x50. */ - elf_tdata (abfd)->core_pid + elf_tdata (abfd)->core->pid = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x50); /* Command name at 0x7c (max 32 bytes, including nul). */ - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 0x7c, 31); return elfcore_make_note_pseudosection (abfd, ".note.netbsdcore.procinfo", @@ -8561,7 +8804,7 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) int lwp; if (elfcore_netbsd_get_lwpid (note, &lwp)) - elf_tdata (abfd)->core_lwpid = lwp; + elf_tdata (abfd)->core->lwpid = lwp; if (note->type == NT_NETBSDCORE_PROCINFO) { @@ -8624,15 +8867,15 @@ static bfd_boolean elfcore_grok_openbsd_procinfo (bfd *abfd, Elf_Internal_Note *note) { /* Signal number at offset 0x08. */ - elf_tdata (abfd)->core_signal + elf_tdata (abfd)->core->signal = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08); /* Process ID at offset 0x20. */ - elf_tdata (abfd)->core_pid + elf_tdata (abfd)->core->pid = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x20); /* Command name at 0x48 (max 32 bytes, including nul). */ - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 0x48, 31); return TRUE; @@ -8695,7 +8938,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid) unsigned flags; /* nto_procfs_status 'pid' field is at offset 0. */ - elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, (bfd_byte *) ddata); + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, (bfd_byte *) ddata); /* nto_procfs_status 'tid' field is at offset 4. Pass it back. */ *tid = bfd_get_32 (abfd, (bfd_byte *) ddata + 4); @@ -8706,15 +8949,15 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid) /* nto_procfs_status 'what' field is at offset 14. */ if ((sig = bfd_get_16 (abfd, (bfd_byte *) ddata + 14)) > 0) { - elf_tdata (abfd)->core_signal = sig; - elf_tdata (abfd)->core_lwpid = *tid; + elf_tdata (abfd)->core->signal = sig; + elf_tdata (abfd)->core->lwpid = *tid; } /* _DEBUG_FLAG_CURTID (current thread) is 0x80. Some cores do not come from signals so we make sure we set the current thread just in case. */ if (flags & 0x00000080) - elf_tdata (abfd)->core_lwpid = *tid; + elf_tdata (abfd)->core->lwpid = *tid; /* Make a ".qnx_core_status/%d" section. */ sprintf (buf, ".qnx_core_status/%ld", *tid); @@ -8762,7 +9005,7 @@ elfcore_grok_nto_regs (bfd *abfd, sect->alignment_power = 2; /* This is the current thread. */ - if (elf_tdata (abfd)->core_lwpid == tid) + if (elf_tdata (abfd)->core->lwpid == tid) return elfcore_maybe_make_sect (abfd, base, sect); return TRUE; @@ -8889,7 +9132,6 @@ elfcore_write_note (bfd *abfd, return buf; } -#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) char * elfcore_write_prpsinfo (bfd *abfd, char *buf, @@ -8897,7 +9139,6 @@ elfcore_write_prpsinfo (bfd *abfd, const char *fname, const char *psargs) { - const char *note_name = "CORE"; const struct elf_backend_data *bed = get_elf_backend_data (abfd); if (bed->elf_backend_write_core_note != NULL) @@ -8909,6 +9150,7 @@ elfcore_write_prpsinfo (bfd *abfd, return ret; } +#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) #if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T) if (bed->s->elfclass == ELFCLASS32) { @@ -8924,7 +9166,7 @@ elfcore_write_prpsinfo (bfd *abfd, 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)); + "CORE", note_type, &data, sizeof (data)); } else #endif @@ -8941,12 +9183,42 @@ elfcore_write_prpsinfo (bfd *abfd, 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)); + "CORE", note_type, &data, sizeof (data)); } -} #endif /* PSINFO_T or PRPSINFO_T */ -#if defined (HAVE_PRSTATUS_T) + free (buf); + return NULL; +} + +char * +elfcore_write_linux_prpsinfo32 + (bfd *abfd, char *buf, int *bufsiz, + const struct elf_internal_linux_prpsinfo *prpsinfo) +{ + struct elf_external_linux_prpsinfo32 data; + + memset (&data, 0, sizeof (data)); + LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data); + + return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO, + &data, sizeof (data)); +} + +char * +elfcore_write_linux_prpsinfo64 + (bfd *abfd, char *buf, int *bufsiz, + const struct elf_internal_linux_prpsinfo *prpsinfo) +{ + struct elf_external_linux_prpsinfo64 data; + + memset (&data, 0, sizeof (data)); + LINUX_PRPSINFO64_SWAP_FIELDS (abfd, prpsinfo, data); + + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", NT_PRPSINFO, &data, sizeof (data)); +} + char * elfcore_write_prstatus (bfd *abfd, char *buf, @@ -8955,7 +9227,6 @@ elfcore_write_prstatus (bfd *abfd, int cursig, const void *gregs) { - const char *note_name = "CORE"; const struct elf_backend_data *bed = get_elf_backend_data (abfd); if (bed->elf_backend_write_core_note != NULL) @@ -8968,6 +9239,7 @@ elfcore_write_prstatus (bfd *abfd, return ret; } +#if defined (HAVE_PRSTATUS_T) #if defined (HAVE_PRSTATUS32_T) if (bed->s->elfclass == ELFCLASS32) { @@ -8977,7 +9249,7 @@ elfcore_write_prstatus (bfd *abfd, prstat.pr_pid = pid; prstat.pr_cursig = cursig; memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg)); - return elfcore_write_note (abfd, buf, bufsiz, note_name, + return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRSTATUS, &prstat, sizeof (prstat)); } else @@ -8989,12 +9261,15 @@ elfcore_write_prstatus (bfd *abfd, prstat.pr_pid = pid; prstat.pr_cursig = cursig; memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg)); - return elfcore_write_note (abfd, buf, bufsiz, note_name, + return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRSTATUS, &prstat, sizeof (prstat)); } -} #endif /* HAVE_PRSTATUS_T */ + free (buf); + return NULL; +} + #if defined (HAVE_LWPSTATUS_T) char * elfcore_write_lwpstatus (bfd *abfd, @@ -9219,6 +9494,18 @@ elfcore_write_s390_system_call (bfd *abfd, s390_system_call, size); } +char * +elfcore_write_s390_tdb (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_tdb, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_TDB, s390_tdb, size); +} + char * elfcore_write_arm_vfp (bfd *abfd, char *buf, @@ -9231,6 +9518,42 @@ elfcore_write_arm_vfp (bfd *abfd, note_name, NT_ARM_VFP, arm_vfp, size); } +char * +elfcore_write_aarch_tls (bfd *abfd, + char *buf, + int *bufsiz, + const void *aarch_tls, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_ARM_TLS, aarch_tls, size); +} + +char * +elfcore_write_aarch_hw_break (bfd *abfd, + char *buf, + int *bufsiz, + const void *aarch_hw_break, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_ARM_HW_BREAK, aarch_hw_break, size); +} + +char * +elfcore_write_aarch_hw_watch (bfd *abfd, + char *buf, + int *bufsiz, + const void *aarch_hw_watch, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_ARM_HW_WATCH, aarch_hw_watch, size); +} + char * elfcore_write_register_note (bfd *abfd, char *buf, @@ -9265,8 +9588,16 @@ elfcore_write_register_note (bfd *abfd, return elfcore_write_s390_last_break (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-s390-system-call") == 0) return elfcore_write_s390_system_call (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-tdb") == 0) + return elfcore_write_s390_tdb (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-arm-vfp") == 0) return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-aarch-tls") == 0) + return elfcore_write_aarch_tls (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-aarch-hw-break") == 0) + return elfcore_write_aarch_hw_break (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-aarch-hw-watch") == 0) + return elfcore_write_aarch_hw_watch (abfd, buf, bufsiz, data, size); return NULL; } @@ -9447,7 +9778,7 @@ _bfd_elf_rela_local_sym (bfd *abfd, + sym->st_value); if ((sec->flags & SEC_MERGE) && ELF_ST_TYPE (sym->st_info) == STT_SECTION - && sec->sec_info_type == ELF_INFO_TYPE_MERGE) + && sec->sec_info_type == SEC_INFO_TYPE_MERGE) { rel->r_addend = _bfd_merged_section_offset (abfd, psec, @@ -9478,7 +9809,7 @@ _bfd_elf_rel_local_sym (bfd *abfd, { asection *sec = *psec; - if (sec->sec_info_type != ELF_INFO_TYPE_MERGE) + if (sec->sec_info_type != SEC_INFO_TYPE_MERGE) return sym->st_value + addend; return _bfd_merged_section_offset (abfd, psec, @@ -9494,10 +9825,10 @@ _bfd_elf_section_offset (bfd *abfd, { switch (sec->sec_info_type) { - case ELF_INFO_TYPE_STABS: + case SEC_INFO_TYPE_STABS: return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info, offset); - case ELF_INFO_TYPE_EH_FRAME: + case SEC_INFO_TYPE_EH_FRAME: return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset); default: if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0) @@ -9528,7 +9859,7 @@ bfd_elf_bfd_from_remote_memory (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma, bfd_byte *, int)) + int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)) { return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory) (templ, ehdr_vma, loadbasep, target_read_memory); @@ -9633,7 +9964,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, if (p->addend != 0) { char buf[30], *a; - + memcpy (names, "+0x", sizeof ("+0x") - 1); names += sizeof ("+0x") - 1; bfd_sprintf_vma (abfd, buf, p->addend); @@ -9685,3 +10016,27 @@ _bfd_elf_is_function_type (unsigned int type) return (type == STT_FUNC || type == STT_GNU_IFUNC); } + +/* If the ELF symbol SYM might be a function in SEC, return the + function size and set *CODE_OFF to the function's entry point, + otherwise return zero. */ + +bfd_size_type +_bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec, + bfd_vma *code_off) +{ + bfd_size_type size; + + if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT + | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0 + || sym->section != sec) + return 0; + + *code_off = sym->value; + size = 0; + if (!(sym->flags & BSF_SYNTHETIC)) + size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size; + if (size == 0) + size = 1; + return size; +} diff --git a/contrib/gdb-7/bfd/elf32-i386.c b/contrib/gdb-7/bfd/elf32-i386.c index d1873051b4..c048e58e90 100644 --- a/contrib/gdb-7/bfd/elf32-i386.c +++ b/contrib/gdb-7/bfd/elf32-i386.c @@ -1,6 +1,6 @@ /* Intel 80386/80486-specific support for 32-bit ELF Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -25,6 +25,7 @@ #include "bfdlink.h" #include "libbfd.h" #include "elf-bfd.h" +#include "elf-nacl.h" #include "elf-vxworks.h" #include "bfd_stdint.h" #include "objalloc.h" @@ -132,7 +133,9 @@ static reloc_howto_type elf_howto_table[]= HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_TPOFF32", TRUE, 0xffffffff, 0xffffffff, FALSE), - EMPTY_HOWTO (38), + HOWTO(R_386_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned, + bfd_elf_generic_reloc, "R_386_SIZE32", + TRUE, 0xffffffff, 0xffffffff, FALSE), HOWTO(R_386_TLS_GOTDESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_GOTDESC", TRUE, 0xffffffff, 0xffffffff, FALSE), @@ -311,6 +314,10 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, TRACE ("BFD_RELOC_386_TLS_TPOFF32"); return &elf_howto_table[R_386_TLS_TPOFF32 - R_386_tls_offset]; + case BFD_RELOC_SIZE32: + TRACE ("BFD_RELOC_SIZE32"); + return &elf_howto_table[R_386_SIZE32 - R_386_tls_offset]; + case BFD_RELOC_386_TLS_GOTDESC: TRACE ("BFD_RELOC_386_TLS_GOTDESC"); return &elf_howto_table[R_386_TLS_GOTDESC - R_386_tls_offset]; @@ -418,10 +425,10 @@ elf_i386_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) return FALSE; /* pr_cursig */ - elf_tdata (abfd)->core_signal = bfd_get_32 (abfd, note->descdata + 20); + elf_tdata (abfd)->core->signal = bfd_get_32 (abfd, note->descdata + 20); /* pr_pid */ - elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 28; @@ -436,10 +443,10 @@ elf_i386_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) case 144: /* Linux/i386 */ /* pr_cursig */ - elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 72; @@ -464,9 +471,9 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) if (pr_version != 1) return FALSE; - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 8, 17); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 25, 81); } else @@ -477,11 +484,11 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return FALSE; case 124: /* Linux/i386 elf_prpsinfo. */ - elf_tdata (abfd)->core_pid + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 12); - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); } } @@ -490,7 +497,7 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) onto the end of the args in some (at least one anyway) implementations, so strip it off if it exists. */ { - char *command = elf_tdata (abfd)->core_command; + char *command = elf_tdata (abfd)->core->command; int n = strlen (command); if (0 < n && command[n - 1] == ' ') @@ -930,7 +937,7 @@ elf_i386_link_hash_table_create (bfd *abfd) struct elf_i386_link_hash_table *ret; bfd_size_type amt = sizeof (struct elf_i386_link_hash_table); - ret = (struct elf_i386_link_hash_table *) bfd_malloc (amt); + ret = (struct elf_i386_link_hash_table *) bfd_zmalloc (amt); if (ret == NULL) return NULL; @@ -943,18 +950,6 @@ elf_i386_link_hash_table_create (bfd *abfd) return NULL; } - ret->sdynbss = NULL; - ret->srelbss = NULL; - ret->plt_eh_frame = NULL; - ret->tls_ldm_got.refcount = 0; - ret->next_tls_desc_index = 0; - ret->sgotplt_jump_table_size = 0; - ret->sym_cache.abfd = NULL; - ret->srelplt2 = NULL; - ret->tls_module_base = NULL; - ret->next_jump_slot_index = 0; - ret->next_irelative_index = 0; - ret->loc_hash_table = htab_try_create (1024, elf_i386_local_htab_hash, elf_i386_local_htab_eq, @@ -981,7 +976,7 @@ elf_i386_link_hash_table_free (struct bfd_link_hash_table *hash) htab_delete (htab->loc_hash_table); if (htab->loc_hash_memory) objalloc_free ((struct objalloc *) htab->loc_hash_memory); - _bfd_generic_link_hash_table_free (hash); + _bfd_elf_link_hash_table_free (hash); } /* Create .plt, .rel.plt, .got, .got.plt, .rel.got, .dynbss, and @@ -1000,9 +995,9 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) if (htab == NULL) return FALSE; - htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); + htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); if (!info->shared) - htab->srelbss = bfd_get_section_by_name (dynobj, ".rel.bss"); + htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss"); if (!htab->sdynbss || (!info->shared && !htab->srelbss)) @@ -1014,22 +1009,17 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) return FALSE; if (!info->no_ld_generated_unwind_info - && bfd_get_section_by_name (dynobj, ".eh_frame") == NULL + && htab->plt_eh_frame == NULL && htab->elf.splt != NULL) { - flagword flags = get_elf_backend_data (dynobj)->dynamic_sec_flags; + flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); htab->plt_eh_frame - = bfd_make_section_with_flags (dynobj, ".eh_frame", - flags | SEC_READONLY); + = bfd_make_section_anyway_with_flags (dynobj, ".eh_frame", flags); if (htab->plt_eh_frame == NULL || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 2)) return FALSE; - - htab->plt_eh_frame->size = sizeof (elf_i386_eh_frame_plt); - htab->plt_eh_frame->contents - = bfd_alloc (dynobj, htab->plt_eh_frame->size); - memcpy (htab->plt_eh_frame->contents, elf_i386_eh_frame_plt, - sizeof (elf_i386_eh_frame_plt)); } return TRUE; @@ -1452,6 +1442,7 @@ elf_i386_check_relocs (bfd *abfd, struct elf_link_hash_entry *h; Elf_Internal_Sym *isym; const char *name; + bfd_boolean size_reloc; r_symndx = ELF32_R_SYM (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info); @@ -1521,73 +1512,8 @@ elf_i386_check_relocs (bfd *abfd, break; } - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle - it here if it is defined in a non-shared object. */ - if (h->type == STT_GNU_IFUNC - && h->def_regular) - { - /* It is referenced by a non-shared object. */ - h->ref_regular = 1; - h->needs_plt = 1; - - /* STT_GNU_IFUNC symbol must go through PLT. */ - h->plt.refcount += 1; - - /* STT_GNU_IFUNC needs dynamic sections. */ - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - switch (r_type) - { - default: - if (h->root.root.string) - name = h->root.root.string; - else - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, - NULL); - (*_bfd_error_handler) - (_("%B: relocation %s against STT_GNU_IFUNC " - "symbol `%s' isn't handled by %s"), abfd, - elf_howto_table[r_type].name, - name, __FUNCTION__); - bfd_set_error (bfd_error_bad_value); - return FALSE; - - case R_386_32: - h->non_got_ref = 1; - h->pointer_equality_needed = 1; - if (info->shared) - { - /* We must copy these reloc types into the - output file. Create a reloc section in - dynobj and make room for this reloc. */ - sreloc = _bfd_elf_create_ifunc_dyn_reloc - (abfd, info, sec, sreloc, - &((struct elf_i386_link_hash_entry *) h)->dyn_relocs); - if (sreloc == NULL) - return FALSE; - } - break; - - case R_386_PC32: - h->non_got_ref = 1; - break; - - case R_386_PLT32: - break; - - case R_386_GOT32: - case R_386_GOTOFF: - h->got.refcount += 1; - if (htab->elf.sgot == NULL - && !_bfd_elf_create_got_section (htab->elf.dynobj, - info)) - return FALSE; - break; - } - - continue; - } + /* It is referenced by a non-shared object. */ + h->ref_regular = 1; } if (! elf_i386_tls_transition (info, abfd, sec, NULL, @@ -1619,6 +1545,10 @@ elf_i386_check_relocs (bfd *abfd, h->plt.refcount += 1; break; + case R_386_SIZE32: + size_reloc = TRUE; + goto do_size; + case R_386_TLS_IE_32: case R_386_TLS_IE: case R_386_TLS_GOTIE: @@ -1711,6 +1641,7 @@ elf_i386_check_relocs (bfd *abfd, (_("%B: `%s' accessed both as normal and " "thread local symbol"), abfd, name); + bfd_set_error (bfd_error_bad_value); return FALSE; } } @@ -1765,6 +1696,8 @@ elf_i386_check_relocs (bfd *abfd, h->pointer_equality_needed = 1; } + size_reloc = FALSE; +do_size: /* If we are creating a shared library, and this is a reloc against a global symbol, or a non PC relative reloc against a local symbol, then we need to copy the reloc @@ -1861,7 +1794,8 @@ elf_i386_check_relocs (bfd *abfd, } p->count += 1; - if (r_type == R_386_PC32) + /* Count size relocation as PC-relative relocation. */ + if (r_type == R_386_PC32 || size_reloc) p->pc_count += 1; } break; @@ -2027,6 +1961,7 @@ elf_i386_gc_sweep_hook (bfd *abfd, case R_386_32: case R_386_PC32: + case R_386_SIZE32: if (info->shared && (h == NULL || h->type != STT_GNU_IFUNC)) break; @@ -2070,10 +2005,44 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, { struct elf_i386_link_hash_table *htab; asection *s; + struct elf_i386_link_hash_entry *eh; + struct elf_dyn_relocs *p; /* STT_GNU_IFUNC symbol must go through PLT. */ if (h->type == STT_GNU_IFUNC) { + /* All local STT_GNU_IFUNC references must be treate as local + calls via local PLT. */ + if (h->ref_regular + && SYMBOL_CALLS_LOCAL (info, h)) + { + bfd_size_type pc_count = 0, count = 0; + struct elf_dyn_relocs **pp; + + eh = (struct elf_i386_link_hash_entry *) h; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + pc_count += p->pc_count; + p->count -= p->pc_count; + p->pc_count = 0; + count += p->count; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + + if (pc_count || count) + { + h->needs_plt = 1; + h->non_got_ref = 1; + if (h->plt.refcount <= 0) + h->plt.refcount = 1; + else + h->plt.refcount += 1; + } + } + if (h->plt.refcount <= 0) { h->plt.offset = (bfd_vma) -1; @@ -2159,9 +2128,6 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, if (ELIMINATE_COPY_RELOCS && !get_elf_i386_backend_data (info->output_bfd)->is_vxworks) { - struct elf_i386_link_hash_entry * eh; - struct elf_dyn_relocs *p; - eh = (struct elf_i386_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) { @@ -2177,13 +2143,6 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, } } - if (h->size == 0) - { - (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), - h->root.root.string); - return TRUE; - } - /* We must allocate the symbol in our .dynbss section, which will become part of the .bss section of the executable. There will be an entry for this symbol in the .dynsym section. The dynamic @@ -2197,7 +2156,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, /* We must generate a R_386_COPY reloc to tell the dynamic linker to copy the initial value out of the dynamic object and into the runtime process image. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) { htab->srelbss->size += sizeof (Elf32_External_Rel); h->needs_copy = 1; @@ -2547,6 +2506,153 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) return TRUE; } +/* Convert + mov foo@GOT(%reg), %reg + to + lea foo@GOTOFF(%reg), %reg + with the local symbol, foo. */ + +static bfd_boolean +elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, + struct bfd_link_info *link_info) +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel, *irelend; + bfd_byte *contents; + struct elf_i386_link_hash_table *htab; + bfd_boolean changed_contents; + bfd_boolean changed_relocs; + bfd_signed_vma *local_got_refcounts; + + /* Don't even try to convert non-ELF outputs. */ + if (!is_elf_hash_table (link_info->hash)) + return FALSE; + + /* Nothing to do if there are no codes, no relocations or no output. */ + if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) + || sec->reloc_count == 0 + || discarded_section (sec)) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + /* Load the relocations for this section. */ + internal_relocs = (_bfd_elf_link_read_relocs + (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, + link_info->keep_memory)); + if (internal_relocs == NULL) + return FALSE; + + htab = elf_i386_hash_table (link_info); + changed_contents = FALSE; + changed_relocs = FALSE; + local_got_refcounts = elf_local_got_refcounts (abfd); + + /* Get the section contents. */ + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + else + { + if (!bfd_malloc_and_get_section (abfd, sec, &contents)) + goto error_return; + } + + irelend = internal_relocs + sec->reloc_count; + for (irel = internal_relocs; irel < irelend; irel++) + { + unsigned int r_type = ELF32_R_TYPE (irel->r_info); + unsigned int r_symndx = ELF32_R_SYM (irel->r_info); + unsigned int indx; + struct elf_link_hash_entry *h; + + if (r_type != R_386_GOT32) + continue; + + /* Get the symbol referred to by the reloc. */ + if (r_symndx < symtab_hdr->sh_info) + { + Elf_Internal_Sym *isym; + + isym = bfd_sym_from_r_symndx (&htab->sym_cache, + abfd, r_symndx); + + /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. */ + if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC + && bfd_get_8 (input_bfd, + contents + irel->r_offset - 2) == 0x8b) + { + bfd_put_8 (output_bfd, 0x8d, + contents + irel->r_offset - 2); + irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); + if (local_got_refcounts != NULL + && local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + changed_contents = TRUE; + changed_relocs = TRUE; + } + continue; + } + + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. We also avoid + optimizing _DYNAMIC since ld.so may use its link-time address. */ + if (h->def_regular + && h->type != STT_GNU_IFUNC + && h != htab->elf.hdynamic + && SYMBOL_REFERENCES_LOCAL (link_info, h) + && bfd_get_8 (input_bfd, + contents + irel->r_offset - 2) == 0x8b) + { + bfd_put_8 (output_bfd, 0x8d, + contents + irel->r_offset - 2); + irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); + if (h->got.refcount > 0) + h->got.refcount -= 1; + changed_contents = TRUE; + changed_relocs = TRUE; + } + } + + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + { + if (!changed_contents && !link_info->keep_memory) + free (contents); + else + { + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; + } + } + + if (elf_section_data (sec)->relocs != internal_relocs) + { + if (!changed_relocs) + free (internal_relocs); + else + elf_section_data (sec)->relocs = internal_relocs; + } + + return TRUE; + + error_return: + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + free (contents); + if (internal_relocs != NULL + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); + return FALSE; +} + /* Set the sizes of the dynamic sections. */ static bfd_boolean @@ -2570,7 +2676,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) /* Set the contents of the .interp section to the interpreter. */ if (info->executable) { - s = bfd_get_section_by_name (dynobj, ".interp"); + s = bfd_get_linker_section (dynobj, ".interp"); if (s == NULL) abort (); s->size = sizeof ELF_DYNAMIC_INTERPRETER; @@ -2597,6 +2703,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { struct elf_dyn_relocs *p; + if (!elf_i386_convert_mov_to_lea (ibfd, s, info)) + return FALSE; + for (p = ((struct elf_dyn_relocs *) elf_section_data (s)->local_dynrel); p != NULL; @@ -2709,7 +2818,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) it's not incremented, so in order to compute the space reserved for them, it suffices to multiply the reloc count by the jump slot size. - + PR ld/13302: We start next_irelative_index at the end of .rela.plt so that R_386_IRELATIVE entries come last. */ if (htab->elf.srelplt) @@ -2724,15 +2833,10 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) if (htab->elf.sgotplt) { - struct elf_link_hash_entry *got; - got = elf_link_hash_lookup (elf_hash_table (info), - "_GLOBAL_OFFSET_TABLE_", - FALSE, FALSE, FALSE); - /* Don't allocate .got.plt section if there are no GOT nor PLT - entries and there is no refeence to _GLOBAL_OFFSET_TABLE_. */ - if ((got == NULL - || !got->ref_regular_nonweak) + entries and there is no reference to _GLOBAL_OFFSET_TABLE_. */ + if ((htab->elf.hgot == NULL + || !htab->elf.hgot->ref_regular_nonweak) && (htab->elf.sgotplt->size == get_elf_backend_data (output_bfd)->got_header_size) && (htab->elf.splt == NULL @@ -2746,6 +2850,14 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) htab->elf.sgotplt->size = 0; } + + if (htab->plt_eh_frame != NULL + && htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && !bfd_is_abs_section (htab->elf.splt->output_section) + && _bfd_elf_eh_frame_present (info)) + htab->plt_eh_frame->size = sizeof (elf_i386_eh_frame_plt); + /* We now have determined the sizes of the various dynamic sections. Allocate memory for them. */ relocs = FALSE; @@ -2757,11 +2869,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) continue; if (s == htab->elf.splt - || s == htab->elf.sgot - || s == htab->elf.sgotplt - || s == htab->elf.iplt - || s == htab->elf.igotplt - || s == htab->sdynbss) + || s == htab->elf.sgot) { /* Strip this section if we don't need it; see the comment below. */ @@ -2772,6 +2880,14 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) if (htab->elf.hplt != NULL) strip_section = FALSE; } + else if (s == htab->elf.sgotplt + || s == htab->elf.iplt + || s == htab->elf.igotplt + || s == htab->plt_eh_frame + || s == htab->sdynbss) + { + /* Strip these too. */ + } else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rel")) { if (s->size != 0 @@ -2819,11 +2935,13 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) } if (htab->plt_eh_frame != NULL - && htab->elf.splt != NULL - && htab->elf.splt->size != 0 - && (htab->elf.splt->flags & SEC_EXCLUDE) == 0) - bfd_put_32 (dynobj, htab->elf.splt->size, - htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); + && htab->plt_eh_frame->contents != NULL) + { + memcpy (htab->plt_eh_frame->contents, elf_i386_eh_frame_plt, + sizeof (elf_i386_eh_frame_plt)); + bfd_put_32 (dynobj, htab->elf.splt->size, + htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); + } if (htab->elf.dynamic_sections_created) { @@ -3070,6 +3188,7 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_reloc_status_type r; unsigned int indx; int tls_type; + bfd_vma st_size; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == R_386_GNU_VTINHERIT @@ -3102,6 +3221,7 @@ elf_i386_relocate_section (bfd *output_bfd, relocation = (sec->output_section->vma + sec->output_offset + sym->st_value); + st_size = sym->st_size; if (ELF_ST_TYPE (sym->st_info) == STT_SECTION && ((sec->flags & SEC_MERGE) != 0 @@ -3194,11 +3314,12 @@ elf_i386_relocate_section (bfd *output_bfd, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, unresolved_reloc, warned); + st_size = h->size; } - if (sec != NULL && elf_discarded_section (sec)) + if (sec != NULL && discarded_section (sec)) RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, relend, howto, contents); + rel, 1, relend, howto, 0, contents); if (info->relocatable) continue; @@ -3254,10 +3375,8 @@ elf_i386_relocate_section (bfd *output_bfd, if (info->shared && h->non_got_ref) { Elf_Internal_Rela outrel; - bfd_byte *loc; asection *sreloc; bfd_vma offset; - bfd_boolean relocate; /* Need a dynamic relocation to get the real function adddress. */ @@ -3278,28 +3397,25 @@ elf_i386_relocate_section (bfd *output_bfd, || info->executable) { /* This symbol is resolved locally. */ - outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); - relocate = TRUE; + outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); + bfd_put_32 (output_bfd, + (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset), + contents + offset); } else - { - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - relocate = FALSE; - } + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); sreloc = htab->elf.irelifunc; - loc = sreloc->contents; - loc += (sreloc->reloc_count++ - * sizeof (Elf32_External_Rel)); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, sreloc, &outrel); /* If this reloc is against an external symbol, we do not want to fiddle with the addend. Otherwise, we need to include the symbol value so that it becomes an addend for the dynamic reloc. For an internal symbol, we have updated addend. */ - if (! relocate) - continue; + continue; } /* FALLTHROUGH */ case R_386_PC32: @@ -3446,7 +3562,6 @@ elf_i386_relocate_section (bfd *output_bfd, { asection *s; Elf_Internal_Rela outrel; - bfd_byte *loc; s = htab->elf.srelgot; if (s == NULL) @@ -3456,9 +3571,7 @@ elf_i386_relocate_section (bfd *output_bfd, + htab->elf.sgot->output_offset + off); outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); - loc = s->contents; - loc += s->reloc_count++ * sizeof (Elf32_External_Rel); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, s, &outrel); } local_got_offsets[r_symndx] |= 1; @@ -3511,6 +3624,7 @@ elf_i386_relocate_section (bfd *output_bfd, return FALSE; } else if (!info->executable + && !SYMBOLIC_BIND (info, h) && h->type == STT_FUNC && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) { @@ -3562,6 +3676,11 @@ elf_i386_relocate_section (bfd *output_bfd, unresolved_reloc = FALSE; break; + case R_386_SIZE32: + /* Set to symbol size. */ + relocation = st_size; + /* Fall through. */ + case R_386_32: case R_386_PC32: if ((input_section->flags & SEC_ALLOC) == 0 @@ -3572,7 +3691,7 @@ elf_i386_relocate_section (bfd *output_bfd, && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak) - && (r_type != R_386_PC32 + && ((r_type != R_386_PC32 && r_type != R_386_SIZE32) || !SYMBOL_CALLS_LOCAL (info, h))) || (ELIMINATE_COPY_RELOCS && !info->shared @@ -3585,7 +3704,6 @@ elf_i386_relocate_section (bfd *output_bfd, || h->root.type == bfd_link_hash_undefined))) { Elf_Internal_Rela outrel; - bfd_byte *loc; bfd_boolean skip, relocate; asection *sreloc; @@ -3630,10 +3748,7 @@ elf_i386_relocate_section (bfd *output_bfd, goto check_relocation_error; } - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); - - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, sreloc, &outrel); /* If this reloc is against an external symbol, we do not want to fiddle with the addend. Otherwise, we @@ -3648,7 +3763,6 @@ elf_i386_relocate_section (bfd *output_bfd, if (!info->executable) { Elf_Internal_Rela outrel; - bfd_byte *loc; asection *sreloc; outrel.r_offset = rel->r_offset @@ -3658,9 +3772,7 @@ elf_i386_relocate_section (bfd *output_bfd, sreloc = elf_section_data (input_section)->sreloc; if (sreloc == NULL) abort (); - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, sreloc, &outrel); } /* Fall through */ @@ -3886,7 +3998,6 @@ elf_i386_relocate_section (bfd *output_bfd, else { Elf_Internal_Rela outrel; - bfd_byte *loc; int dr_type; asection *sreloc; @@ -3897,6 +4008,7 @@ elf_i386_relocate_section (bfd *output_bfd, if (GOT_TLS_GDESC_P (tls_type)) { + bfd_byte *loc; outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_DESC); BFD_ASSERT (htab->sgotplt_jump_table_size + offplt + 8 <= htab->elf.sgotplt->size); @@ -3954,11 +4066,7 @@ elf_i386_relocate_section (bfd *output_bfd, htab->elf.sgot->contents + off); outrel.r_info = ELF32_R_INFO (indx, dr_type); - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); - BFD_ASSERT (loc + sizeof (Elf32_External_Rel) - <= sreloc->contents + sreloc->size); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, sreloc, &outrel); if (GOT_TLS_GD_P (tls_type)) { @@ -3976,11 +4084,7 @@ elf_i386_relocate_section (bfd *output_bfd, outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_DTPOFF32); outrel.r_offset += 4; - sreloc->reloc_count++; - loc += sizeof (Elf32_External_Rel); - BFD_ASSERT (loc + sizeof (Elf32_External_Rel) - <= sreloc->contents + sreloc->size); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, sreloc, &outrel); } } else if (tls_type == GOT_TLS_IE_BOTH) @@ -3992,9 +4096,7 @@ elf_i386_relocate_section (bfd *output_bfd, htab->elf.sgot->contents + off + 4); outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); outrel.r_offset += 4; - sreloc->reloc_count++; - loc += sizeof (Elf32_External_Rel); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, sreloc, &outrel); } dr_done: @@ -4176,7 +4278,6 @@ elf_i386_relocate_section (bfd *output_bfd, else { Elf_Internal_Rela outrel; - bfd_byte *loc; if (htab->elf.srelgot == NULL) abort (); @@ -4189,9 +4290,7 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_put_32 (output_bfd, 0, htab->elf.sgot->contents + off + 4); outrel.r_info = ELF32_R_INFO (0, R_386_TLS_DTPMOD32); - loc = htab->elf.srelgot->contents; - loc += htab->elf.srelgot->reloc_count++ * sizeof (Elf32_External_Rel); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, htab->elf.srelgot, &outrel); htab->tls_ldm_got.offset |= 1; } relocation = htab->elf.sgot->output_section->vma @@ -4215,7 +4314,6 @@ elf_i386_relocate_section (bfd *output_bfd, { Elf_Internal_Rela outrel; asection *sreloc; - bfd_byte *loc; outrel.r_offset = rel->r_offset + input_section->output_section->vma @@ -4231,9 +4329,7 @@ elf_i386_relocate_section (bfd *output_bfd, sreloc = elf_section_data (input_section)->sreloc; if (sreloc == NULL) abort (); - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + elf_append_rel (output_bfd, sreloc, &outrel); if (indx) continue; else if (r_type == R_386_TLS_LE_32) @@ -4368,7 +4464,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, || plt == NULL || gotplt == NULL || relplt == NULL) - return FALSE; + abort (); /* Get the index in the procedure linkage table which corresponds to this symbol. This is the index of this symbol @@ -4438,7 +4534,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, + got_offset); rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32); bfd_elf32_swap_reloc_out (output_bfd, &rel, - loc + sizeof (Elf32_External_Rel)); + loc + sizeof (Elf32_External_Rel)); } } else @@ -4521,7 +4617,6 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE) == 0) { Elf_Internal_Rela rel; - bfd_byte *loc; /* This symbol has an entry in the global offset table. Set it up. */ @@ -4579,15 +4674,12 @@ do_glob_dat: rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); } - loc = htab->elf.srelgot->contents; - loc += htab->elf.srelgot->reloc_count++ * sizeof (Elf32_External_Rel); - bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + elf_append_rel (output_bfd, htab->elf.srelgot, &rel); } if (h->needs_copy) { Elf_Internal_Rela rel; - bfd_byte *loc; /* This symbol needs a copy reloc. Set it up. */ @@ -4601,22 +4693,9 @@ do_glob_dat: + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY); - loc = htab->srelbss->contents; - loc += htab->srelbss->reloc_count++ * sizeof (Elf32_External_Rel); - bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + elf_append_rel (output_bfd, htab->srelbss, &rel); } - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. SYM may - be NULL for local symbols. - - On VxWorks, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it - is relative to the ".got" section. */ - if (sym != NULL - && (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || (!abed->is_vxworks - && h == htab->elf.hgot))) - sym->st_shndx = SHN_ABS; - return TRUE; } @@ -4670,7 +4749,7 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, return FALSE; dynobj = htab->elf.dynobj; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); abed = get_elf_i386_backend_data (output_bfd); if (htab->elf.dynamic_sections_created) @@ -4855,7 +4934,8 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, } /* Adjust .eh_frame for .plt section. */ - if (htab->plt_eh_frame != NULL) + if (htab->plt_eh_frame != NULL + && htab->plt_eh_frame->contents != NULL) { if (htab->elf.splt != NULL && htab->elf.splt->size != 0 @@ -4872,7 +4952,7 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, + PLT_FDE_START_OFFSET); } if (htab->plt_eh_frame->sec_info_type - == ELF_INFO_TYPE_EH_FRAME) + == SEC_INFO_TYPE_EH_FRAME) { if (! _bfd_elf_write_section_eh_frame (output_bfd, info, htab->plt_eh_frame, @@ -5117,7 +5197,10 @@ elf_i386_nacl_pic_plt0_entry[sizeof (elf_i386_nacl_plt0_entry)] = 0x8b, 0x4b, 0x08, /* mov 0x8(%ebx), %ecx */ 0x83, 0xe1, 0xe0, /* and $NACLMASK, %ecx */ 0xff, 0xe1, /* jmp *%ecx */ - 0x90 /* nop */ + + /* This is expected to be the same size as elf_i386_nacl_plt0_entry, + so pad to that size with nop instructions. */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; static const bfd_byte elf_i386_nacl_pic_plt_entry[NACL_PLT_ENTRY_SIZE] = @@ -5211,8 +5294,17 @@ static const struct elf_i386_backend_data elf_i386_nacl_arch_bed = #undef elf_backend_arch_data #define elf_backend_arch_data &elf_i386_nacl_arch_bed +#undef elf_backend_modify_segment_map +#define elf_backend_modify_segment_map nacl_modify_segment_map +#undef elf_backend_modify_program_headers +#define elf_backend_modify_program_headers nacl_modify_program_headers + #include "elf32-target.h" +/* Restore defaults. */ +#undef elf_backend_modify_segment_map +#undef elf_backend_modify_program_headers + /* VxWorks support. */ #undef TARGET_LITTLE_SYM diff --git a/contrib/gdb-7/bfd/elf64-x86-64.c b/contrib/gdb-7/bfd/elf64-x86-64.c index fe0db0e8dc..9406479d66 100644 --- a/contrib/gdb-7/bfd/elf64-x86-64.c +++ b/contrib/gdb-7/bfd/elf64-x86-64.c @@ -26,6 +26,7 @@ #include "bfdlink.h" #include "libbfd.h" #include "elf-bfd.h" +#include "elf-nacl.h" #include "bfd_stdint.h" #include "objalloc.h" #include "hashtab.h" @@ -147,8 +148,12 @@ static reloc_howto_type x86_64_elf_howto_table[] = HOWTO(R_X86_64_PLTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_PLTOFF64", FALSE, MINUS_ONE, MINUS_ONE, FALSE), - EMPTY_HOWTO (32), - EMPTY_HOWTO (33), + HOWTO(R_X86_64_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned, + bfd_elf_generic_reloc, "R_X86_64_SIZE32", FALSE, 0xffffffff, 0xffffffff, + FALSE), + HOWTO(R_X86_64_SIZE64, 0, 4, 64, FALSE, 0, complain_overflow_unsigned, + bfd_elf_generic_reloc, "R_X86_64_SIZE64", FALSE, MINUS_ONE, MINUS_ONE, + FALSE), HOWTO(R_X86_64_GOTPC32_TLSDESC, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_GOTPC32_TLSDESC", @@ -172,7 +177,7 @@ static reloc_howto_type x86_64_elf_howto_table[] = R_X86_64_standard counts the number up to this point, and R_X86_64_vt_offset is the value to subtract from a reloc type of R_X86_64_GNU_VT* to form an index into this table. */ -#define R_X86_64_standard (R_X86_64_IRELATIVE + 1) +#define R_X86_64_standard (R_X86_64_RELATIVE64 + 1) #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) /* GNU extension to record C++ vtable hierarchy. */ @@ -237,6 +242,8 @@ static const struct elf_reloc_map x86_64_reloc_map[] = { BFD_RELOC_X86_64_GOTPC64, R_X86_64_GOTPC64, }, { BFD_RELOC_X86_64_GOTPLT64, R_X86_64_GOTPLT64, }, { BFD_RELOC_X86_64_PLTOFF64, R_X86_64_PLTOFF64, }, + { BFD_RELOC_SIZE32, R_X86_64_SIZE32, }, + { BFD_RELOC_SIZE64, R_X86_64_SIZE64, }, { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, }, { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, }, { BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, }, @@ -341,10 +348,10 @@ elf_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) case 296: /* sizeof(istruct elf_prstatus) on Linux/x32 */ /* pr_cursig */ - elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 72; @@ -354,11 +361,11 @@ elf_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) case 336: /* sizeof(istruct elf_prstatus) on Linux/x86_64 */ /* pr_cursig */ - elf_tdata (abfd)->core_signal + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_lwpid + elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32); /* pr_reg */ @@ -382,20 +389,20 @@ elf_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return FALSE; case 124: /* sizeof(struct elf_prpsinfo) on Linux/x32 */ - elf_tdata (abfd)->core_pid + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 12); - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); break; case 136: /* sizeof(struct elf_prpsinfo) on Linux/x86_64 */ - elf_tdata (abfd)->core_pid + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); } @@ -404,7 +411,7 @@ elf_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) implementations, so strip it off if it exists. */ { - char *command = elf_tdata (abfd)->core_command; + char *command = elf_tdata (abfd)->core->command; int n = strlen (command); if (0 < n && command[n - 1] == ' ') @@ -448,7 +455,7 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz, } else { - prpsinfo_t data; + prpsinfo64_t data; memset (&data, 0, sizeof (data)); strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); @@ -489,7 +496,7 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz, } else { - prstatus_t prstat; + prstatus64_t prstat; memset (&prstat, 0, sizeof (prstat)); prstat.pr_pid = pid; prstat.pr_cursig = cursig; @@ -508,7 +515,7 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz, section. */ #define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1" -#define ELF32_DYNAMIC_INTERPRETER "/lib/ld32.so.1" +#define ELF32_DYNAMIC_INTERPRETER "/lib/ldx32.so.1" /* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid copying dynamic variables from a shared lib into an app's dynbss @@ -585,6 +592,70 @@ static const bfd_byte elf_x86_64_eh_frame_plt[] = DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop }; +/* Architecture-specific backend data for x86-64. */ + +struct elf_x86_64_backend_data +{ + /* Templates for the initial PLT entry and for subsequent entries. */ + const bfd_byte *plt0_entry; + const bfd_byte *plt_entry; + unsigned int plt_entry_size; /* Size of each PLT entry. */ + + /* Offsets into plt0_entry that are to be replaced with GOT[1] and GOT[2]. */ + unsigned int plt0_got1_offset; + unsigned int plt0_got2_offset; + + /* Offset of the end of the PC-relative instruction containing + plt0_got2_offset. */ + unsigned int plt0_got2_insn_end; + + /* Offsets into plt_entry that are to be replaced with... */ + unsigned int plt_got_offset; /* ... address of this symbol in .got. */ + unsigned int plt_reloc_offset; /* ... offset into relocation table. */ + unsigned int plt_plt_offset; /* ... offset to start of .plt. */ + + /* Length of the PC-relative instruction containing plt_got_offset. */ + unsigned int plt_got_insn_size; + + /* Offset of the end of the PC-relative jump to plt0_entry. */ + unsigned int plt_plt_insn_end; + + /* Offset into plt_entry where the initial value of the GOT entry points. */ + unsigned int plt_lazy_offset; + + /* .eh_frame covering the .plt section. */ + const bfd_byte *eh_frame_plt; + unsigned int eh_frame_plt_size; +}; + +#define get_elf_x86_64_backend_data(abfd) \ + ((const struct elf_x86_64_backend_data *) \ + get_elf_backend_data (abfd)->arch_data) + +#define GET_PLT_ENTRY_SIZE(abfd) \ + get_elf_x86_64_backend_data (abfd)->plt_entry_size + +/* These are the standard parameters. */ +static const struct elf_x86_64_backend_data elf_x86_64_arch_bed = + { + elf_x86_64_plt0_entry, /* plt0_entry */ + elf_x86_64_plt_entry, /* plt_entry */ + sizeof (elf_x86_64_plt_entry), /* plt_entry_size */ + 2, /* plt0_got1_offset */ + 8, /* plt0_got2_offset */ + 12, /* plt0_got2_insn_end */ + 2, /* plt_got_offset */ + 7, /* plt_reloc_offset */ + 12, /* plt_plt_offset */ + 6, /* plt_got_insn_size */ + PLT_ENTRY_SIZE, /* plt_plt_insn_end */ + 6, /* plt_lazy_offset */ + elf_x86_64_eh_frame_plt, /* eh_frame_plt */ + sizeof (elf_x86_64_eh_frame_plt), /* eh_frame_plt_size */ + }; + +#define elf_backend_arch_data &elf_x86_64_arch_bed + /* x86-64 ELF linker hash entry. */ struct elf_x86_64_link_hash_entry @@ -721,8 +792,8 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry, if (entry == NULL) { entry = (struct bfd_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct elf_x86_64_link_hash_entry)); + bfd_hash_allocate (table, + sizeof (struct elf_x86_64_link_hash_entry)); if (entry == NULL) return entry; } @@ -817,7 +888,7 @@ elf_x86_64_link_hash_table_create (bfd *abfd) struct elf_x86_64_link_hash_table *ret; bfd_size_type amt = sizeof (struct elf_x86_64_link_hash_table); - ret = (struct elf_x86_64_link_hash_table *) bfd_malloc (amt); + ret = (struct elf_x86_64_link_hash_table *) bfd_zmalloc (amt); if (ret == NULL) return NULL; @@ -830,18 +901,6 @@ elf_x86_64_link_hash_table_create (bfd *abfd) return NULL; } - ret->sdynbss = NULL; - ret->srelbss = NULL; - ret->plt_eh_frame = NULL; - ret->sym_cache.abfd = NULL; - ret->tlsdesc_plt = 0; - ret->tlsdesc_got = 0; - ret->tls_ld_got.refcount = 0; - ret->sgotplt_jump_table_size = 0; - ret->tls_module_base = NULL; - ret->next_jump_slot_index = 0; - ret->next_irelative_index = 0; - if (ABI_64_P (abfd)) { ret->r_info = elf64_r_info; @@ -885,7 +944,7 @@ elf_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash) htab_delete (htab->loc_hash_table); if (htab->loc_hash_memory) objalloc_free ((struct objalloc *) htab->loc_hash_memory); - _bfd_generic_link_hash_table_free (hash); + _bfd_elf_link_hash_table_free (hash); } /* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and @@ -905,31 +964,26 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj, if (htab == NULL) return FALSE; - htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); + htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); if (!info->shared) - htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss"); + htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss"); if (!htab->sdynbss || (!info->shared && !htab->srelbss)) abort (); if (!info->no_ld_generated_unwind_info - && bfd_get_section_by_name (dynobj, ".eh_frame") == NULL + && htab->plt_eh_frame == NULL && htab->elf.splt != NULL) { - flagword flags = get_elf_backend_data (dynobj)->dynamic_sec_flags; + flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); htab->plt_eh_frame - = bfd_make_section_with_flags (dynobj, ".eh_frame", - flags | SEC_READONLY); + = bfd_make_section_anyway_with_flags (dynobj, ".eh_frame", flags); if (htab->plt_eh_frame == NULL || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 3)) return FALSE; - - htab->plt_eh_frame->size = sizeof (elf_x86_64_eh_frame_plt); - htab->plt_eh_frame->contents - = bfd_alloc (dynobj, htab->plt_eh_frame->size); - memcpy (htab->plt_eh_frame->contents, elf_x86_64_eh_frame_plt, - sizeof (elf_x86_64_eh_frame_plt)); } return TRUE; } @@ -1009,6 +1063,14 @@ elf64_x86_64_elf_object_p (bfd *abfd) return TRUE; } +static bfd_boolean +elf32_x86_64_elf_object_p (bfd *abfd) +{ + /* Set the right machine number for an x86-64 elf32 file. */ + bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x64_32); + return TRUE; +} + /* Return TRUE if the TLS access code sequence support transition from R_TYPE. */ @@ -1107,7 +1169,7 @@ elf_x86_64_check_tls_transition (bfd *abfd, h = sym_hashes[r_symndx - symtab_hdr->sh_info]; /* Use strncmp to check __tls_get_addr since __tls_get_addr - may be versioned. */ + may be versioned. */ return (h != NULL && h->root.root.string != NULL && (ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PC32 @@ -1350,6 +1412,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, struct elf_link_hash_entry *h; Elf_Internal_Sym *isym; const char *name; + bfd_boolean size_reloc; r_symndx = htab->r_sym (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info); @@ -1454,82 +1517,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, break; } - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle - it here if it is defined in a non-shared object. */ - if (h->type == STT_GNU_IFUNC - && h->def_regular) - { - /* It is referenced by a non-shared object. */ - h->ref_regular = 1; - h->needs_plt = 1; - - /* STT_GNU_IFUNC symbol must go through PLT. */ - h->plt.refcount += 1; - - /* STT_GNU_IFUNC needs dynamic sections. */ - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - switch (r_type) - { - default: - if (h->root.root.string) - name = h->root.root.string; - else - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, - NULL); - (*_bfd_error_handler) - (_("%B: relocation %s against STT_GNU_IFUNC " - "symbol `%s' isn't handled by %s"), abfd, - x86_64_elf_howto_table[r_type].name, - name, __FUNCTION__); - bfd_set_error (bfd_error_bad_value); - return FALSE; - - case R_X86_64_32: - if (ABI_64_P (abfd)) - goto not_pointer; - case R_X86_64_64: - h->non_got_ref = 1; - h->pointer_equality_needed = 1; - if (info->shared) - { - /* We must copy these reloc types into the output - file. Create a reloc section in dynobj and - make room for this reloc. */ - sreloc = _bfd_elf_create_ifunc_dyn_reloc - (abfd, info, sec, sreloc, - &((struct elf_x86_64_link_hash_entry *) h)->dyn_relocs); - if (sreloc == NULL) - return FALSE; - } - break; - - case R_X86_64_32S: - case R_X86_64_PC32: - case R_X86_64_PC64: -not_pointer: - h->non_got_ref = 1; - if (r_type != R_X86_64_PC32 - && r_type != R_X86_64_PC64) - h->pointer_equality_needed = 1; - break; - - case R_X86_64_PLT32: - break; - - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCREL64: - h->got.refcount += 1; - if (htab->elf.sgot == NULL - && !_bfd_elf_create_got_section (htab->elf.dynobj, - info)) - return FALSE; - break; - } - - continue; - } + /* It is referenced by a non-shared object. */ + h->ref_regular = 1; } if (! elf_x86_64_tls_transition (info, abfd, sec, NULL, @@ -1650,6 +1639,7 @@ not_pointer: (*_bfd_error_handler) (_("%B: '%s' accessed both as normal and thread local symbol"), abfd, name); + bfd_set_error (bfd_error_bad_value); return FALSE; } } @@ -1705,6 +1695,11 @@ not_pointer: } goto create_got; + case R_X86_64_SIZE32: + case R_X86_64_SIZE64: + size_reloc = TRUE; + goto do_size; + case R_X86_64_32: if (!ABI_64_P (abfd)) goto pointer; @@ -1754,6 +1749,8 @@ pointer: h->pointer_equality_needed = 1; } + size_reloc = FALSE; +do_size: /* If we are creating a shared library, and this is a reloc against a global symbol, or a non PC relative reloc against a local symbol, then we need to copy the reloc @@ -1854,7 +1851,8 @@ pointer: } p->count += 1; - if (IS_X86_64_PCREL_TYPE (r_type)) + /* Count size relocation as PC-relative relocation. */ + if (IS_X86_64_PCREL_TYPE (r_type) || size_reloc) p->pc_count += 1; } break; @@ -2007,7 +2005,7 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, if (h != NULL) { if (r_type == R_X86_64_GOTPLT64 && h->plt.refcount > 0) - h->plt.refcount -= 1; + h->plt.refcount -= 1; if (h->got.refcount > 0) h->got.refcount -= 1; if (h->type == STT_GNU_IFUNC) @@ -2032,6 +2030,8 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_X86_64_PC16: case R_X86_64_PC32: case R_X86_64_PC64: + case R_X86_64_SIZE32: + case R_X86_64_SIZE64: if (info->shared && (h == NULL || h->type != STT_GNU_IFUNC)) break; @@ -2066,10 +2066,44 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, { struct elf_x86_64_link_hash_table *htab; asection *s; + struct elf_x86_64_link_hash_entry *eh; + struct elf_dyn_relocs *p; /* STT_GNU_IFUNC symbol must go through PLT. */ if (h->type == STT_GNU_IFUNC) { + /* All local STT_GNU_IFUNC references must be treate as local + calls via local PLT. */ + if (h->ref_regular + && SYMBOL_CALLS_LOCAL (info, h)) + { + bfd_size_type pc_count = 0, count = 0; + struct elf_dyn_relocs **pp; + + eh = (struct elf_x86_64_link_hash_entry *) h; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + pc_count += p->pc_count; + p->count -= p->pc_count; + p->pc_count = 0; + count += p->count; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + + if (pc_count || count) + { + h->needs_plt = 1; + h->non_got_ref = 1; + if (h->plt.refcount <= 0) + h->plt.refcount = 1; + else + h->plt.refcount += 1; + } + } + if (h->plt.refcount <= 0) { h->plt.offset = (bfd_vma) -1; @@ -2146,9 +2180,6 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, if (ELIMINATE_COPY_RELOCS) { - struct elf_x86_64_link_hash_entry * eh; - struct elf_dyn_relocs *p; - eh = (struct elf_x86_64_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) { @@ -2166,13 +2197,6 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, } } - if (h->size == 0) - { - (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), - h->root.root.string); - return TRUE; - } - /* We must allocate the symbol in our .dynbss section, which will become part of the .bss section of the executable. There will be an entry for this symbol in the .dynsym section. The dynamic @@ -2190,7 +2214,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, /* We must generate a R_X86_64_COPY reloc to tell the dynamic linker to copy the initial value out of the dynamic object and into the runtime process image. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) { const struct elf_backend_data *bed; bed = get_elf_backend_data (info->output_bfd); @@ -2214,6 +2238,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) struct elf_x86_64_link_hash_entry *eh; struct elf_dyn_relocs *p; const struct elf_backend_data *bed; + unsigned int plt_entry_size; if (h->root.type == bfd_link_hash_indirect) return TRUE; @@ -2225,6 +2250,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) if (htab == NULL) return FALSE; bed = get_elf_backend_data (info->output_bfd); + plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined and referenced in a non-shared object. */ @@ -2232,7 +2258,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) && h->def_regular) return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, - PLT_ENTRY_SIZE, + plt_entry_size, GOT_ENTRY_SIZE); else if (htab->elf.dynamic_sections_created && h->plt.refcount > 0) @@ -2254,7 +2280,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* If this is the first .plt entry, make room for the special first entry. */ if (s->size == 0) - s->size += PLT_ENTRY_SIZE; + s->size += plt_entry_size; h->plt.offset = s->size; @@ -2271,7 +2297,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) } /* Make room for this entry. */ - s->size += PLT_ENTRY_SIZE; + s->size += plt_entry_size; /* We also need to make an entry in the .got.plt section, which will be placed in the .got section by the linker script. */ @@ -2509,6 +2535,154 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, return TRUE; } +/* Convert + mov foo@GOTPCREL(%rip), %reg + to + lea foo(%rip), %reg + with the local symbol, foo. */ + +static bfd_boolean +elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, + struct bfd_link_info *link_info) +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel, *irelend; + bfd_byte *contents; + struct elf_x86_64_link_hash_table *htab; + bfd_boolean changed_contents; + bfd_boolean changed_relocs; + bfd_signed_vma *local_got_refcounts; + + /* Don't even try to convert non-ELF outputs. */ + if (!is_elf_hash_table (link_info->hash)) + return FALSE; + + /* Nothing to do if there are no codes, no relocations or no output. */ + if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) + || sec->reloc_count == 0 + || discarded_section (sec)) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + /* Load the relocations for this section. */ + internal_relocs = (_bfd_elf_link_read_relocs + (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, + link_info->keep_memory)); + if (internal_relocs == NULL) + return FALSE; + + htab = elf_x86_64_hash_table (link_info); + changed_contents = FALSE; + changed_relocs = FALSE; + local_got_refcounts = elf_local_got_refcounts (abfd); + + /* Get the section contents. */ + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + else + { + if (!bfd_malloc_and_get_section (abfd, sec, &contents)) + goto error_return; + } + + irelend = internal_relocs + sec->reloc_count; + for (irel = internal_relocs; irel < irelend; irel++) + { + unsigned int r_type = ELF32_R_TYPE (irel->r_info); + unsigned int r_symndx = htab->r_sym (irel->r_info); + unsigned int indx; + struct elf_link_hash_entry *h; + + if (r_type != R_X86_64_GOTPCREL) + continue; + + /* Get the symbol referred to by the reloc. */ + if (r_symndx < symtab_hdr->sh_info) + { + Elf_Internal_Sym *isym; + + isym = bfd_sym_from_r_symndx (&htab->sym_cache, + abfd, r_symndx); + + /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. */ + if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC + && bfd_get_8 (input_bfd, + contents + irel->r_offset - 2) == 0x8b) + { + bfd_put_8 (output_bfd, 0x8d, + contents + irel->r_offset - 2); + irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32); + if (local_got_refcounts != NULL + && local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + changed_contents = TRUE; + changed_relocs = TRUE; + } + continue; + } + + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. We also + avoid optimizing _DYNAMIC since ld.so may use its link-time + address. */ + if (h->def_regular + && h->type != STT_GNU_IFUNC + && h != htab->elf.hdynamic + && SYMBOL_REFERENCES_LOCAL (link_info, h) + && bfd_get_8 (input_bfd, + contents + irel->r_offset - 2) == 0x8b) + { + bfd_put_8 (output_bfd, 0x8d, + contents + irel->r_offset - 2); + irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32); + if (h->got.refcount > 0) + h->got.refcount -= 1; + changed_contents = TRUE; + changed_relocs = TRUE; + } + } + + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + { + if (!changed_contents && !link_info->keep_memory) + free (contents); + else + { + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; + } + } + + if (elf_section_data (sec)->relocs != internal_relocs) + { + if (!changed_relocs) + free (internal_relocs); + else + elf_section_data (sec)->relocs = internal_relocs; + } + + return TRUE; + + error_return: + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + free (contents); + if (internal_relocs != NULL + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); + return FALSE; +} + /* Set the sizes of the dynamic sections. */ static bfd_boolean @@ -2536,7 +2710,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, /* Set the contents of the .interp section to the interpreter. */ if (info->executable) { - s = bfd_get_section_by_name (dynobj, ".interp"); + s = bfd_get_linker_section (dynobj, ".interp"); if (s == NULL) abort (); s->size = htab->dynamic_interpreter_size; @@ -2563,6 +2737,9 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, { struct elf_dyn_relocs *p; + if (!elf_x86_64_convert_mov_to_lea (ibfd, s, info)) + return FALSE; + for (p = (struct elf_dyn_relocs *) (elf_section_data (s)->local_dynrel); p != NULL; @@ -2695,23 +2872,18 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, /* Reserve room for the initial entry. FIXME: we could probably do away with it in this case. */ if (htab->elf.splt->size == 0) - htab->elf.splt->size += PLT_ENTRY_SIZE; + htab->elf.splt->size += GET_PLT_ENTRY_SIZE (output_bfd); htab->tlsdesc_plt = htab->elf.splt->size; - htab->elf.splt->size += PLT_ENTRY_SIZE; + htab->elf.splt->size += GET_PLT_ENTRY_SIZE (output_bfd); } } if (htab->elf.sgotplt) { - struct elf_link_hash_entry *got; - got = elf_link_hash_lookup (elf_hash_table (info), - "_GLOBAL_OFFSET_TABLE_", - FALSE, FALSE, FALSE); - /* Don't allocate .got.plt section if there are no GOT nor PLT - entries and there is no refeence to _GLOBAL_OFFSET_TABLE_. */ - if ((got == NULL - || !got->ref_regular_nonweak) + entries and there is no refeence to _GLOBAL_OFFSET_TABLE_. */ + if ((htab->elf.hgot == NULL + || !htab->elf.hgot->ref_regular_nonweak) && (htab->elf.sgotplt->size == get_elf_backend_data (output_bfd)->got_header_size) && (htab->elf.splt == NULL @@ -2725,6 +2897,17 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, htab->elf.sgotplt->size = 0; } + if (htab->plt_eh_frame != NULL + && htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && !bfd_is_abs_section (htab->elf.splt->output_section) + && _bfd_elf_eh_frame_present (info)) + { + const struct elf_x86_64_backend_data *arch_data + = (const struct elf_x86_64_backend_data *) bed->arch_data; + htab->plt_eh_frame->size = arch_data->eh_frame_plt_size; + } + /* We now have determined the sizes of the various dynamic sections. Allocate memory for them. */ relocs = FALSE; @@ -2738,6 +2921,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, || s == htab->elf.sgotplt || s == htab->elf.iplt || s == htab->elf.igotplt + || s == htab->plt_eh_frame || s == htab->sdynbss) { /* Strip this section if we don't need it; see the @@ -2789,11 +2973,16 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, } if (htab->plt_eh_frame != NULL - && htab->elf.splt != NULL - && htab->elf.splt->size != 0 - && (htab->elf.splt->flags & SEC_EXCLUDE) == 0) - bfd_put_32 (dynobj, htab->elf.splt->size, - htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); + && htab->plt_eh_frame->contents != NULL) + { + const struct elf_x86_64_backend_data *arch_data + = (const struct elf_x86_64_backend_data *) bed->arch_data; + + memcpy (htab->plt_eh_frame->contents, + arch_data->eh_frame_plt, htab->plt_eh_frame->size); + bfd_put_32 (dynobj, htab->elf.splt->size, + htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); + } if (htab->elf.dynamic_sections_created) { @@ -2835,7 +3024,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, + elf_link_hash_traverse (&htab->elf, elf_x86_64_readonly_dynrelocs, info); @@ -2988,6 +3177,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, bfd_vma *local_tlsdesc_gotents; Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; + const unsigned int plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); BFD_ASSERT (is_x86_64_elf (input_bfd)); @@ -3017,20 +3207,24 @@ elf_x86_64_relocate_section (bfd *output_bfd, bfd_reloc_status_type r; int tls_type; asection *base_got; + bfd_vma st_size; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == (int) R_X86_64_GNU_VTINHERIT || r_type == (int) R_X86_64_GNU_VTENTRY) continue; - if (r_type >= R_X86_64_max) + if (r_type >= (int) R_X86_64_standard) { + (*_bfd_error_handler) + (_("%B: unrecognized relocation (0x%x) in section `%A'"), + input_bfd, input_section, r_type); bfd_set_error (bfd_error_bad_value); return FALSE; } if (r_type != (int) R_X86_64_32 - || ABI_64_P (output_bfd)) + || ABI_64_P (output_bfd)) howto = x86_64_elf_howto_table + r_type; else howto = (x86_64_elf_howto_table @@ -3047,6 +3241,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + st_size = sym->st_size; /* Relocate against local STT_GNU_IFUNC symbol. */ if (!info->relocatable @@ -3057,7 +3252,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (h == NULL) abort (); - /* Set STT_GNU_IFUNC symbol value. */ + /* Set STT_GNU_IFUNC symbol value. */ h->root.u.def.value = sym->st_value; h->root.u.def.section = sec; } @@ -3070,23 +3265,32 @@ elf_x86_64_relocate_section (bfd *output_bfd, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, unresolved_reloc, warned); + st_size = h->size; } - if (sec != NULL && elf_discarded_section (sec)) + if (sec != NULL && discarded_section (sec)) RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, relend, howto, contents); + rel, 1, relend, howto, 0, contents); if (info->relocatable) continue; - if (rel->r_addend == 0 - && r_type == R_X86_64_64 - && !ABI_64_P (output_bfd)) + if (rel->r_addend == 0 && !ABI_64_P (output_bfd)) { - /* For x32, treat R_X86_64_64 like R_X86_64_32 and zero-extend - it to 64bit if addend is zero. */ - r_type = R_X86_64_32; - memset (contents + rel->r_offset + 4, 0, 4); + if (r_type == R_X86_64_64) + { + /* For x32, treat R_X86_64_64 like R_X86_64_32 and + zero-extend it to 64bit if addend is zero. */ + r_type = R_X86_64_32; + memset (contents + rel->r_offset + 4, 0, 4); + } + else if (r_type == R_X86_64_SIZE64) + { + /* For x32, treat R_X86_64_SIZE64 like R_X86_64_SIZE32 and + zero-extend it to 64bit if addend is zero. */ + r_type = R_X86_64_SIZE32; + memset (contents + rel->r_offset + 4, 0, 4); + } } /* Since STT_GNU_IFUNC symbol must go through PLT, we handle @@ -3133,7 +3337,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (ABI_64_P (output_bfd)) goto do_relocation; /* FALLTHROUGH */ - case R_X86_64_64: + case R_X86_64_64: if (rel->r_addend != 0) { if (h->root.root.string) @@ -3156,7 +3360,6 @@ elf_x86_64_relocate_section (bfd *output_bfd, { Elf_Internal_Rela outrel; asection *sreloc; - bfd_boolean relocate; /* Need a dynamic relocation to get the real function address. */ @@ -3176,15 +3379,15 @@ elf_x86_64_relocate_section (bfd *output_bfd, || info->executable) { /* This symbol is resolved locally. */ - outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE); - outrel.r_addend = relocation; - relocate = FALSE; + outrel.r_info = htab->r_info (0, R_X86_64_IRELATIVE); + outrel.r_addend = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); } else { outrel.r_info = htab->r_info (h->dynindx, r_type); outrel.r_addend = 0; - relocate = FALSE; } sreloc = htab->elf.irelifunc; @@ -3195,8 +3398,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, we need to include the symbol value so that it becomes an addend for the dynamic reloc. For an internal symbol, we have updated addend. */ - if (! relocate) - continue; + continue; } /* FALLTHROUGH */ case R_X86_64_PC32: @@ -3220,13 +3422,13 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (htab->elf.splt != NULL) { - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; + plt_index = h->plt.offset / plt_entry_size - 1; off = (plt_index + 3) * GOT_ENTRY_SIZE; base_got = htab->elf.sgotplt; } else { - plt_index = h->plt.offset / PLT_ENTRY_SIZE; + plt_index = h->plt.offset / plt_entry_size; off = plt_index * GOT_ENTRY_SIZE; base_got = htab->elf.igotplt; } @@ -3235,9 +3437,9 @@ elf_x86_64_relocate_section (bfd *output_bfd, || h->forced_local || info->symbolic) { - /* This references the local defitionion. We must + /* This references the local defitionion. We must initialize this entry in the global offset table. - Since the offset must always be a multiple of 8, + Since the offset must always be a multiple of 8, we use the least significant bit to record whether we have initialized it already. @@ -3293,14 +3495,14 @@ elf_x86_64_relocate_section (bfd *output_bfd, off = h->got.offset; if (h->needs_plt - && h->plt.offset != (bfd_vma)-1 + && h->plt.offset != (bfd_vma)-1 && off == (bfd_vma)-1) { /* We can't use h->got.offset here to save state, or even just remember the offset, as finish_dynamic_symbol would use that as offset into .got. */ - bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; + bfd_vma plt_index = h->plt.offset / plt_entry_size - 1; off = (plt_index + 3) * GOT_ENTRY_SIZE; base_got = htab->elf.sgotplt; } @@ -3331,7 +3533,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, bfd_put_64 (output_bfd, relocation, base_got->contents + off); /* Note that this is harmless for the GOTPLT64 case, - as -1 | 1 still is -1. */ + as -1 | 1 still is -1. */ h->got.offset |= 1; } } @@ -3396,8 +3598,9 @@ elf_x86_64_relocate_section (bfd *output_bfd, /* Check to make sure it isn't a protected function symbol for shared library since it may not be local when used as function address. */ - if (info->shared + if (!info->executable && h + && !SYMBOLIC_BIND (info, h) && h->def_regular && h->type == STT_FUNC && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) @@ -3429,7 +3632,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, case R_X86_64_PLTOFF64: /* Relocation is PLT entry relative to GOT. For local symbols it's the symbol itself relative to GOT. */ - if (h != NULL + if (h != NULL /* See PLT32 handling. */ && h->plt.offset != (bfd_vma) -1 && htab->elf.splt != NULL) @@ -3468,11 +3671,16 @@ elf_x86_64_relocate_section (bfd *output_bfd, unresolved_reloc = FALSE; break; + case R_X86_64_SIZE32: + case R_X86_64_SIZE64: + /* Set to symbol size. */ + relocation = st_size; + goto direct; + case R_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: if (info->shared - && ABI_64_P (output_bfd) && (input_section->flags & SEC_ALLOC) != 0 && (input_section->flags & SEC_READONLY) != 0 && h != NULL) @@ -3541,6 +3749,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, /* FIXME: The ABI says the linker should make sure the value is the same when it's zeroextended to 64 bit. */ +direct: if ((input_section->flags & SEC_ALLOC) == 0) break; @@ -3548,7 +3757,9 @@ elf_x86_64_relocate_section (bfd *output_bfd, && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak) - && (! IS_X86_64_PCREL_TYPE (r_type) + && ((! IS_X86_64_PCREL_TYPE (r_type) + && r_type != R_X86_64_SIZE32 + && r_type != R_X86_64_SIZE64) || ! SYMBOL_CALLS_LOCAL (info, h))) || (ELIMINATE_COPY_RELOCS && !info->shared @@ -3612,6 +3823,36 @@ elf_x86_64_relocate_section (bfd *output_bfd, outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE64); outrel.r_addend = relocation + rel->r_addend; + /* Check addend overflow. */ + if ((outrel.r_addend & 0x80000000) + != (rel->r_addend & 0x80000000)) + { + const char *name; + int addend = rel->r_addend; + if (h && h->root.root.string) + name = h->root.root.string; + else + name = bfd_elf_sym_name (input_bfd, symtab_hdr, + sym, NULL); + if (addend < 0) + (*_bfd_error_handler) + (_("%B: addend -0x%x in relocation %s against " + "symbol `%s' at 0x%lx in section `%A' is " + "out of range"), + input_bfd, input_section, addend, + x86_64_elf_howto_table[r_type].name, + name, (unsigned long) rel->r_offset); + else + (*_bfd_error_handler) + (_("%B: addend 0x%x in relocation %s against " + "symbol `%s' at 0x%lx in section `%A' is " + "out of range"), + input_bfd, input_section, addend, + x86_64_elf_howto_table[r_type].name, + name, (unsigned long) rel->r_offset); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } } else { @@ -4101,13 +4342,16 @@ elf_x86_64_relocate_section (bfd *output_bfd, && h->def_dynamic) && _bfd_elf_section_offset (output_bfd, info, input_section, rel->r_offset) != (bfd_vma) -1) - (*_bfd_error_handler) - (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - (long) rel->r_offset, - howto->name, - h->root.root.string); + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), + input_bfd, + input_section, + (long) rel->r_offset, + howto->name, + h->root.root.string); + return FALSE; + } do_relocation: r = _bfd_final_link_relocate (howto, input_bfd, input_section, @@ -4161,9 +4405,11 @@ static bfd_boolean elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) + Elf_Internal_Sym *sym ATTRIBUTE_UNUSED) { struct elf_x86_64_link_hash_table *htab; + const struct elf_x86_64_backend_data *const abed + = get_elf_x86_64_backend_data (output_bfd); htab = elf_x86_64_hash_table (info); if (htab == NULL) @@ -4202,7 +4448,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, || plt == NULL || gotplt == NULL || relplt == NULL) - return FALSE; + abort (); /* Get the index in the procedure linkage table which corresponds to this symbol. This is the index of this symbol @@ -4217,39 +4463,38 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, if (plt == htab->elf.splt) { - got_offset = h->plt.offset / PLT_ENTRY_SIZE - 1; + got_offset = h->plt.offset / abed->plt_entry_size - 1; got_offset = (got_offset + 3) * GOT_ENTRY_SIZE; } else { - got_offset = h->plt.offset / PLT_ENTRY_SIZE; + got_offset = h->plt.offset / abed->plt_entry_size; got_offset = got_offset * GOT_ENTRY_SIZE; } /* Fill in the entry in the procedure linkage table. */ - memcpy (plt->contents + h->plt.offset, elf_x86_64_plt_entry, - PLT_ENTRY_SIZE); - - /* Insert the relocation positions of the plt section. The magic - numbers at the end of the statements are the positions of the - relocations in the plt section. */ - /* Put offset for jmp *name@GOTPCREL(%rip), since the - instruction uses 6 bytes, subtract this value. */ + memcpy (plt->contents + h->plt.offset, abed->plt_entry, + abed->plt_entry_size); + + /* Insert the relocation positions of the plt section. */ + + /* Put offset the PC-relative instruction referring to the GOT entry, + subtracting the size of that instruction. */ bfd_put_32 (output_bfd, - (gotplt->output_section->vma - + gotplt->output_offset - + got_offset - - plt->output_section->vma - - plt->output_offset - - h->plt.offset - - 6), - plt->contents + h->plt.offset + 2); + (gotplt->output_section->vma + + gotplt->output_offset + + got_offset + - plt->output_section->vma + - plt->output_offset + - h->plt.offset + - abed->plt_got_insn_size), + plt->contents + h->plt.offset + abed->plt_got_offset); /* Fill in the entry in the global offset table, initially this - points to the pushq instruction in the PLT which is at offset 6. */ + points to the second part of the PLT entry. */ bfd_put_64 (output_bfd, (plt->output_section->vma + plt->output_offset - + h->plt.offset + 6), + + h->plt.offset + abed->plt_lazy_offset), gotplt->contents + got_offset); /* Fill in the entry in the .rela.plt section. */ @@ -4283,10 +4528,10 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, { /* Put relocation index. */ bfd_put_32 (output_bfd, plt_index, - plt->contents + h->plt.offset + 7); + plt->contents + h->plt.offset + abed->plt_reloc_offset); /* Put offset for jmp .PLT0. */ - bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE), - plt->contents + h->plt.offset + 12); + bfd_put_32 (output_bfd, - (h->plt.offset + abed->plt_plt_insn_end), + plt->contents + h->plt.offset + abed->plt_plt_offset); } bed = get_elf_backend_data (output_bfd); @@ -4399,13 +4644,6 @@ do_glob_dat: elf_append_rela (output_bfd, htab->srelbss, &rela); } - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. SYM may - be NULL for local symbols. */ - if (sym != NULL - && (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || h == htab->elf.hgot)) - sym->st_shndx = SHN_ABS; - return TRUE; } @@ -4418,7 +4656,7 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf) struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot; struct bfd_link_info *info - = (struct bfd_link_info *) inf; + = (struct bfd_link_info *) inf; return elf_x86_64_finish_dynamic_symbol (info->output_bfd, info, h, NULL); @@ -4433,6 +4671,7 @@ elf_x86_64_reloc_type_class (const Elf_Internal_Rela *rela) switch ((int) ELF32_R_TYPE (rela->r_info)) { case R_X86_64_RELATIVE: + case R_X86_64_RELATIVE64: return reloc_class_relative; case R_X86_64_JUMP_SLOT: return reloc_class_plt; @@ -4452,13 +4691,15 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, struct elf_x86_64_link_hash_table *htab; bfd *dynobj; asection *sdyn; + const struct elf_x86_64_backend_data *const abed + = get_elf_x86_64_backend_data (output_bfd); htab = elf_x86_64_hash_table (info); if (htab == NULL) return FALSE; dynobj = htab->elf.dynobj; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); if (htab->elf.dynamic_sections_created) { @@ -4534,8 +4775,8 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, if (htab->elf.splt && htab->elf.splt->size > 0) { /* Fill in the first entry in the procedure linkage table. */ - memcpy (htab->elf.splt->contents, elf_x86_64_plt0_entry, - PLT_ENTRY_SIZE); + memcpy (htab->elf.splt->contents, + abed->plt0_entry, abed->plt_entry_size); /* Add offset for pushq GOT+8(%rip), since the instruction uses 6 bytes subtract this value. */ bfd_put_32 (output_bfd, @@ -4545,20 +4786,20 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - htab->elf.splt->output_section->vma - htab->elf.splt->output_offset - 6), - htab->elf.splt->contents + 2); - /* Add offset for jmp *GOT+16(%rip). The 12 is the offset to - the end of the instruction. */ + htab->elf.splt->contents + abed->plt0_got1_offset); + /* Add offset for the PC-relative instruction accessing GOT+16, + subtracting the offset to the end of that instruction. */ bfd_put_32 (output_bfd, (htab->elf.sgotplt->output_section->vma + htab->elf.sgotplt->output_offset + 16 - htab->elf.splt->output_section->vma - htab->elf.splt->output_offset - - 12), - htab->elf.splt->contents + 8); + - abed->plt0_got2_insn_end), + htab->elf.splt->contents + abed->plt0_got2_offset); - elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize = - PLT_ENTRY_SIZE; + elf_section_data (htab->elf.splt->output_section) + ->this_hdr.sh_entsize = abed->plt_entry_size; if (htab->tlsdesc_plt) { @@ -4566,8 +4807,7 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, htab->elf.sgot->contents + htab->tlsdesc_got); memcpy (htab->elf.splt->contents + htab->tlsdesc_plt, - elf_x86_64_plt0_entry, - PLT_ENTRY_SIZE); + abed->plt0_entry, abed->plt_entry_size); /* Add offset for pushq GOT+8(%rip), since the instruction uses 6 bytes subtract this value. */ @@ -4579,10 +4819,11 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - htab->elf.splt->output_offset - htab->tlsdesc_plt - 6), - htab->elf.splt->contents + htab->tlsdesc_plt + 2); - /* Add offset for jmp *GOT+TDG(%rip), where TGD stands for - htab->tlsdesc_got. The 12 is the offset to the end of - the instruction. */ + htab->elf.splt->contents + + htab->tlsdesc_plt + abed->plt0_got1_offset); + /* Add offset for the PC-relative instruction accessing GOT+TDG, + where TGD stands for htab->tlsdesc_got, subtracting the offset + to the end of that instruction. */ bfd_put_32 (output_bfd, (htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset @@ -4590,8 +4831,9 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - htab->elf.splt->output_section->vma - htab->elf.splt->output_offset - htab->tlsdesc_plt - - 12), - htab->elf.splt->contents + htab->tlsdesc_plt + 8); + - abed->plt0_got2_insn_end), + htab->elf.splt->contents + + htab->tlsdesc_plt + abed->plt0_got2_offset); } } } @@ -4626,7 +4868,8 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, } /* Adjust .eh_frame for .plt section. */ - if (htab->plt_eh_frame != NULL) + if (htab->plt_eh_frame != NULL + && htab->plt_eh_frame->contents != NULL) { if (htab->elf.splt != NULL && htab->elf.splt->size != 0 @@ -4642,8 +4885,7 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, htab->plt_eh_frame->contents + PLT_FDE_START_OFFSET); } - if (htab->plt_eh_frame->sec_info_type - == ELF_INFO_TYPE_EH_FRAME) + if (htab->plt_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME) { if (! _bfd_elf_write_section_eh_frame (output_bfd, info, htab->plt_eh_frame, @@ -4671,7 +4913,7 @@ static bfd_vma elf_x86_64_plt_sym_val (bfd_vma i, const asection *plt, const arelent *rel ATTRIBUTE_UNUSED) { - return plt->vma + (i + 1) * PLT_ENTRY_SIZE; + return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner); } /* Handle an x86-64 specific section when reading an object file. This @@ -5024,6 +5266,189 @@ static const struct bfd_elf_special_section #include "elf64-target.h" +/* Native Client support. */ + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM bfd_elf64_x86_64_nacl_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf64-x86-64-nacl" +#undef elf64_bed +#define elf64_bed elf64_x86_64_nacl_bed + +#undef ELF_MAXPAGESIZE +#undef ELF_MINPAGESIZE +#undef ELF_COMMONPAGESIZE +#define ELF_MAXPAGESIZE 0x10000 +#define ELF_MINPAGESIZE 0x10000 +#define ELF_COMMONPAGESIZE 0x10000 + +/* Restore defaults. */ +#undef ELF_OSABI +#undef elf_backend_static_tls_alignment +#undef elf_backend_want_plt_sym +#define elf_backend_want_plt_sym 0 + +/* NaCl uses substantially different PLT entries for the same effects. */ + +#undef elf_backend_plt_alignment +#define elf_backend_plt_alignment 5 +#define NACL_PLT_ENTRY_SIZE 64 +#define NACLMASK 0xe0 /* 32-byte alignment mask. */ + +static const bfd_byte elf_x86_64_nacl_plt0_entry[NACL_PLT_ENTRY_SIZE] = + { + 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ + 0x4c, 0x8b, 0x1d, 16, 0, 0, 0, /* mov GOT+16(%rip), %r11 */ + 0x41, 0x83, 0xe3, NACLMASK, /* and $-32, %r11d */ + 0x4d, 0x01, 0xfb, /* add %r15, %r11 */ + 0x41, 0xff, 0xe3, /* jmpq *%r11 */ + + /* 9-byte nop sequence to pad out to the next 32-byte boundary. */ + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopl %cs:0x0(%rax,%rax,1) */ + + /* 32 bytes of nop to pad out to the standard size. */ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data32 prefixes */ + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw %cs:0x0(%rax,%rax,1) */ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data32 prefixes */ + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw %cs:0x0(%rax,%rax,1) */ + 0x66, /* excess data32 prefix */ + 0x90 /* nop */ + }; + +static const bfd_byte elf_x86_64_nacl_plt_entry[NACL_PLT_ENTRY_SIZE] = + { + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, /* mov name@GOTPCREL(%rip),%r11 */ + 0x41, 0x83, 0xe3, NACLMASK, /* and $-32, %r11d */ + 0x4d, 0x01, 0xfb, /* add %r15, %r11 */ + 0x41, 0xff, 0xe3, /* jmpq *%r11 */ + + /* 15-byte nop sequence to pad out to the next 32-byte boundary. */ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data32 prefixes */ + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw %cs:0x0(%rax,%rax,1) */ + + /* Lazy GOT entries point here (32-byte aligned). */ + 0x68, /* pushq immediate */ + 0, 0, 0, 0, /* replaced with index into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0, /* replaced with offset to start of .plt0. */ + + /* 22 bytes of nop to pad out to the standard size. */ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data32 prefixes */ + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw %cs:0x0(%rax,%rax,1) */ + 0x0f, 0x1f, 0x80, 0, 0, 0, 0, /* nopl 0x0(%rax) */ + }; + +/* .eh_frame covering the .plt section. */ + +static const bfd_byte elf_x86_64_nacl_eh_frame_plt[] = + { +#if (PLT_CIE_LENGTH != 20 \ + || PLT_FDE_LENGTH != 36 \ + || PLT_FDE_START_OFFSET != 4 + PLT_CIE_LENGTH + 8 \ + || PLT_FDE_LEN_OFFSET != 4 + PLT_CIE_LENGTH + 12) +# error "Need elf_x86_64_backend_data parameters for eh_frame_plt offsets!" +#endif + PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ + 0, 0, 0, 0, /* CIE ID */ + 1, /* CIE version */ + 'z', 'R', 0, /* Augmentation string */ + 1, /* Code alignment factor */ + 0x78, /* Data alignment factor */ + 16, /* Return address column */ + 1, /* Augmentation size */ + DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ + DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */ + DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */ + DW_CFA_nop, DW_CFA_nop, + + PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ + PLT_CIE_LENGTH + 8, 0, 0, 0,/* CIE pointer */ + 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */ + 0, 0, 0, 0, /* .plt size goes here */ + 0, /* Augmentation size */ + DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */ + DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ + DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */ + DW_CFA_advance_loc + 58, /* DW_CFA_advance_loc: 58 to __PLT__+64 */ + DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ + 13, /* Block length */ + DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */ + DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */ + DW_OP_const1u, 63, DW_OP_and, DW_OP_const1u, 37, DW_OP_ge, + DW_OP_lit3, DW_OP_shl, DW_OP_plus, + DW_CFA_nop, DW_CFA_nop + }; + +static const struct elf_x86_64_backend_data elf_x86_64_nacl_arch_bed = + { + elf_x86_64_nacl_plt0_entry, /* plt0_entry */ + elf_x86_64_nacl_plt_entry, /* plt_entry */ + NACL_PLT_ENTRY_SIZE, /* plt_entry_size */ + 2, /* plt0_got1_offset */ + 9, /* plt0_got2_offset */ + 13, /* plt0_got2_insn_end */ + 3, /* plt_got_offset */ + 33, /* plt_reloc_offset */ + 38, /* plt_plt_offset */ + 7, /* plt_got_insn_size */ + 42, /* plt_plt_insn_end */ + 32, /* plt_lazy_offset */ + elf_x86_64_nacl_eh_frame_plt, /* eh_frame_plt */ + sizeof (elf_x86_64_nacl_eh_frame_plt), /* eh_frame_plt_size */ + }; + +#undef elf_backend_arch_data +#define elf_backend_arch_data &elf_x86_64_nacl_arch_bed + +#undef elf_backend_modify_segment_map +#define elf_backend_modify_segment_map nacl_modify_segment_map +#undef elf_backend_modify_program_headers +#define elf_backend_modify_program_headers nacl_modify_program_headers + +#include "elf64-target.h" + +/* Native Client x32 support. */ + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM bfd_elf32_x86_64_nacl_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf32-x86-64-nacl" +#undef elf32_bed +#define elf32_bed elf32_x86_64_nacl_bed + +#define bfd_elf32_bfd_link_hash_table_create \ + elf_x86_64_link_hash_table_create +#define bfd_elf32_bfd_link_hash_table_free \ + elf_x86_64_link_hash_table_free +#define bfd_elf32_bfd_reloc_type_lookup \ + elf_x86_64_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup \ + elf_x86_64_reloc_name_lookup +#define bfd_elf32_mkobject \ + elf_x86_64_mkobject + +#undef elf_backend_object_p +#define elf_backend_object_p \ + elf32_x86_64_elf_object_p + +#undef elf_backend_bfd_from_remote_memory +#define elf_backend_bfd_from_remote_memory \ + _bfd_elf32_bfd_from_remote_memory + +#undef elf_backend_size_info +#define elf_backend_size_info \ + _bfd_elf32_size_info + +#include "elf32-target.h" + +/* Restore defaults. */ +#undef elf_backend_object_p +#define elf_backend_object_p elf64_x86_64_elf_object_p +#undef elf_backend_bfd_from_remote_memory +#undef elf_backend_size_info +#undef elf_backend_modify_segment_map +#undef elf_backend_modify_program_headers + /* Intel L1OM support. */ static bfd_boolean @@ -5052,10 +5477,17 @@ elf64_l1om_elf_object_p (bfd *abfd) #undef elf_backend_object_p #define elf_backend_object_p elf64_l1om_elf_object_p -#undef elf_backend_static_tls_alignment - -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 0 +/* Restore defaults. */ +#undef ELF_MAXPAGESIZE +#undef ELF_MINPAGESIZE +#undef ELF_COMMONPAGESIZE +#define ELF_MAXPAGESIZE 0x200000 +#define ELF_MINPAGESIZE 0x1000 +#define ELF_COMMONPAGESIZE 0x1000 +#undef elf_backend_plt_alignment +#define elf_backend_plt_alignment 4 +#undef elf_backend_arch_data +#define elf_backend_arch_data &elf_x86_64_arch_bed #include "elf64-target.h" @@ -5126,18 +5558,11 @@ elf64_k1om_elf_object_p (bfd *abfd) /* 32bit x86-64 support. */ -static bfd_boolean -elf32_x86_64_elf_object_p (bfd *abfd) -{ - /* Set the right machine number for an x86-64 elf32 file. */ - bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x64_32); - return TRUE; -} - #undef TARGET_LITTLE_SYM #define TARGET_LITTLE_SYM bfd_elf32_x86_64_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-x86-64" +#undef elf32_bed #undef ELF_ARCH #define ELF_ARCH bfd_arch_i386 @@ -5145,17 +5570,6 @@ elf32_x86_64_elf_object_p (bfd *abfd) #undef ELF_MACHINE_CODE #define ELF_MACHINE_CODE EM_X86_64 -#define bfd_elf32_bfd_link_hash_table_create \ - elf_x86_64_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_free \ - elf_x86_64_link_hash_table_free -#define bfd_elf32_bfd_reloc_type_lookup \ - elf_x86_64_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - elf_x86_64_reloc_name_lookup -#define bfd_elf32_mkobject \ - elf_x86_64_mkobject - #undef ELF_OSABI #undef elf_backend_object_p diff --git a/contrib/gdb-7/bfd/elfcode.h b/contrib/gdb-7/bfd/elfcode.h index b7e022614c..e296c5ce78 100644 --- a/contrib/gdb-7/bfd/elfcode.h +++ b/contrib/gdb-7/bfd/elfcode.h @@ -1,6 +1,6 @@ /* ELF executable support for BFD. Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Written by Fred Fish @ Cygnus Support, from information published @@ -495,13 +495,10 @@ elf_object_p (bfd *abfd) Elf_Internal_Shdr *i_shdrp; /* Section header table, internal form */ unsigned int shindex; const struct elf_backend_data *ebd; - struct bfd_preserve preserve; asection *s; bfd_size_type amt; const bfd_target *target; - preserve.marker = NULL; - /* Read in the ELF header in external format. */ if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) @@ -539,9 +536,6 @@ elf_object_p (bfd *abfd) goto got_wrong_format_error; } - if (!bfd_preserve_save (abfd, &preserve)) - goto got_no_match; - target = abfd->xvec; /* Allocate an instance of the elf_obj_tdata structure and hook it up to @@ -549,7 +543,6 @@ elf_object_p (bfd *abfd) if (! (*target->_bfd_set_format[bfd_object]) (abfd)) goto got_no_match; - preserve.marker = elf_tdata (abfd); /* Now that we know the byte order, swap in the rest of the header */ i_ehdrp = elf_elfheader (abfd); @@ -633,8 +626,9 @@ elf_object_p (bfd *abfd) if (i_ehdrp->e_shnum == SHN_UNDEF) { i_ehdrp->e_shnum = i_shdr.sh_size; - if (i_ehdrp->e_shnum != i_shdr.sh_size - || i_ehdrp->e_shnum == 0) + if (i_ehdrp->e_shnum >= SHN_LORESERVE + || i_ehdrp->e_shnum != i_shdr.sh_size + || i_ehdrp->e_shnum == 0) goto got_wrong_format_error; } @@ -841,25 +835,12 @@ elf_object_p (bfd *abfd) s->flags |= SEC_DEBUGGING; } } - - bfd_preserve_finish (abfd, &preserve); return target; got_wrong_format_error: - /* There is way too much undoing of half-known state here. The caller, - bfd_check_format_matches, really shouldn't iterate on live bfd's to - check match/no-match like it does. We have to rely on that a call to - bfd_default_set_arch_mach with the previously known mach, undoes what - was done by the first bfd_default_set_arch_mach (with mach 0) here. - For this to work, only elf-data and the mach may be changed by the - target-specific elf_backend_object_p function. Note that saving the - whole bfd here and restoring it would be even worse; the first thing - you notice is that the cached bfd file position gets out of sync. */ bfd_set_error (bfd_error_wrong_format); got_no_match: - if (preserve.marker != NULL) - bfd_preserve_restore (abfd, &preserve); return NULL; } @@ -1090,6 +1071,7 @@ elf_checksum_contents (bfd *abfd, { Elf_Internal_Shdr i_shdr; Elf_External_Shdr x_shdr; + bfd_byte *contents, *free_contents; i_shdr = *i_shdrp[count]; i_shdr.sh_offset = 0; @@ -1097,8 +1079,36 @@ elf_checksum_contents (bfd *abfd, elf_swap_shdr_out (abfd, &i_shdr, &x_shdr); (*process) (&x_shdr, sizeof x_shdr, arg); - if (i_shdr.contents) - (*process) (i_shdr.contents, i_shdr.sh_size, arg); + /* Process the section's contents, if it has some. + PR ld/12451: Read them in if necessary. */ + if (i_shdr.sh_type == SHT_NOBITS) + continue; + free_contents = NULL; + contents = i_shdr.contents; + if (contents == NULL) + { + asection *sec; + + sec = bfd_section_from_elf_index (abfd, count); + if (sec != NULL) + { + contents = sec->contents; + if (contents == NULL) + { + /* Force rereading from file. */ + sec->flags &= ~SEC_IN_MEMORY; + if (!bfd_malloc_and_get_section (abfd, sec, &free_contents)) + continue; + contents = free_contents; + } + } + } + if (contents != NULL) + { + (*process) (contents, i_shdr.sh_size, arg); + if (free_contents != NULL) + free (free_contents); + } } return TRUE; @@ -1142,9 +1152,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) verhdr = NULL; else verhdr = &elf_tdata (abfd)->dynversym_hdr; - if ((elf_tdata (abfd)->dynverdef_section != 0 + if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL) - || (elf_tdata (abfd)->dynverref_section != 0 + || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL)) { if (!_bfd_elf_slurp_version_tables (abfd, FALSE)) @@ -1430,7 +1440,7 @@ elf_slurp_reloc_table_from_section (bfd *abfd, (*_bfd_error_handler) (_("%s(%s): relocation %d has invalid symbol index %ld"), abfd->filename, asect->name, i, ELF_R_SYM (rela.r_info)); - relent->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; } else { @@ -1595,7 +1605,7 @@ NAME(_bfd_elf,bfd_from_remote_memory) (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma, bfd_byte *, int)) + int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)) { Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */ diff --git a/contrib/gdb-7/bfd/elfcore.h b/contrib/gdb-7/bfd/elfcore.h index 81980c0fec..429c09c758 100644 --- a/contrib/gdb-7/bfd/elfcore.h +++ b/contrib/gdb-7/bfd/elfcore.h @@ -22,19 +22,19 @@ char* elf_core_file_failing_command (bfd *abfd) { - return elf_tdata (abfd)->core_command; + return elf_tdata (abfd)->core->command; } int elf_core_file_failing_signal (bfd *abfd) { - return elf_tdata (abfd)->core_signal; + return elf_tdata (abfd)->core->signal; } int elf_core_file_pid (bfd *abfd) { - return elf_tdata (abfd)->core_pid; + return elf_tdata (abfd)->core->pid; } bfd_boolean @@ -51,7 +51,7 @@ elf_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) } /* See if the name in the corefile matches the executable name. */ - corename = elf_tdata (core_bfd)->core_program; + corename = elf_tdata (core_bfd)->core->program; if (corename != NULL) { const char* execname = strrchr (exec_bfd->filename, '/'); @@ -84,11 +84,8 @@ elf_core_file_p (bfd *abfd) Elf_Internal_Phdr *i_phdrp; /* Elf program header, internal form. */ unsigned int phindex; const struct elf_backend_data *ebd; - struct bfd_preserve preserve; bfd_size_type amt; - preserve.marker = NULL; - /* Read in the ELF header in external format. */ if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) { @@ -123,13 +120,9 @@ elf_core_file_p (bfd *abfd) goto wrong; } - if (!bfd_preserve_save (abfd, &preserve)) - goto fail; - /* Give abfd an elf_obj_tdata. */ if (! (*abfd->xvec->_bfd_set_format[bfd_core]) (abfd)) goto fail; - preserve.marker = elf_tdata (abfd); /* Swap in the rest of the header, now that we have the byte order. */ i_ehdrp = elf_elfheader (abfd); @@ -294,7 +287,7 @@ elf_core_file_p (bfd *abfd) { bfd_size_type high = 0; struct stat statbuf; - for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) + for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) { Elf_Internal_Phdr *p = i_phdrp + phindex; if (p->p_filesz) @@ -315,27 +308,13 @@ elf_core_file_p (bfd *abfd) } } } - + /* Save the entry point from the ELF header. */ bfd_get_start_address (abfd) = i_ehdrp->e_entry; - - bfd_preserve_finish (abfd, &preserve); return abfd->xvec; wrong: - /* There is way too much undoing of half-known state here. The caller, - bfd_check_format_matches, really shouldn't iterate on live bfd's to - check match/no-match like it does. We have to rely on that a call to - bfd_default_set_arch_mach with the previously known mach, undoes what - was done by the first bfd_default_set_arch_mach (with mach 0) here. - For this to work, only elf-data and the mach may be changed by the - target-specific elf_backend_object_p function. Note that saving the - whole bfd here and restoring it would be even worse; the first thing - you notice is that the cached bfd file position gets out of sync. */ bfd_set_error (bfd_error_wrong_format); - fail: - if (preserve.marker != NULL) - bfd_preserve_restore (abfd, &preserve); return NULL; } diff --git a/contrib/gdb-7/bfd/elflink.c b/contrib/gdb-7/bfd/elflink.c index 1d1ca0bce4..ba65f21aaa 100644 --- a/contrib/gdb-7/bfd/elflink.c +++ b/contrib/gdb-7/bfd/elflink.c @@ -1,6 +1,6 @@ /* ELF linking support for BFD. Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -104,8 +104,8 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) struct elf_link_hash_table *htab = elf_hash_table (info); /* This function may be called more than once. */ - s = bfd_get_section_by_name (abfd, ".got"); - if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0) + s = bfd_get_linker_section (abfd, ".got"); + if (s != NULL) return TRUE; flags = bed->dynamic_sec_flags; @@ -187,6 +187,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) flagword flags; asection *s; const struct elf_backend_data *bed; + struct elf_link_hash_entry *h; if (! is_elf_hash_table (info->hash)) return FALSE; @@ -254,7 +255,9 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) section. We don't want to define it if there is no .dynamic section, since on some ELF platforms the start up code examines it to decide how to initialize the process. */ - if (!_bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC")) + h = _bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC"); + elf_hash_table (info)->hdynamic = h; + if (h == NULL) return FALSE; if (info->emit_hash) @@ -569,7 +572,7 @@ bfd_elf_record_link_assignment (bfd *output_bfd, h->def_regular = 1; - if (provide && hidden) + if (hidden) { bed = get_elf_backend_data (output_bfd); h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; @@ -779,8 +782,7 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, asection *ip; if (htab->dynobj != NULL - && (ip = bfd_get_section_by_name (htab->dynobj, p->name)) != NULL - && (ip->flags & SEC_LINKER_CREATED) + && (ip = bfd_get_linker_section (htab->dynobj, p->name)) != NULL && ip->output_section == p) return TRUE; } @@ -912,6 +914,7 @@ _bfd_elf_merge_symbol (bfd *abfd, Elf_Internal_Sym *sym, asection **psec, bfd_vma *pvalue, + bfd_boolean *pold_weak, unsigned int *pold_alignment, struct elf_link_hash_entry **sym_hash, bfd_boolean *skip, @@ -921,6 +924,7 @@ _bfd_elf_merge_symbol (bfd *abfd, { asection *sec, *oldsec; struct elf_link_hash_entry *h; + struct elf_link_hash_entry *hi; struct elf_link_hash_entry *flip; int bind; bfd *oldbfd; @@ -937,7 +941,7 @@ _bfd_elf_merge_symbol (bfd *abfd, /* Silently discard TLS symbols from --just-syms. There's no way to combine a static TLS block with a new TLS block for this executable. */ if (ELF_ST_TYPE (sym->st_info) == STT_TLS - && sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS) + && sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) { *skip = TRUE; return TRUE; @@ -959,17 +963,47 @@ _bfd_elf_merge_symbol (bfd *abfd, if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) return TRUE; - /* For merging, we only care about real symbols. */ - + /* For merging, we only care about real symbols. But we need to make + sure that indirect symbol dynamic flags are updated. */ + hi = h; while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; /* We have to check it for every instance since the first few may be - refereences and not all compilers emit symbol type for undefined + references and not all compilers emit symbol type for undefined symbols. */ bfd_elf_link_mark_dynamic_symbol (info, h, sym); + /* NEWDYN and OLDDYN indicate whether the new or old symbol, + respectively, is from a dynamic object. */ + + newdyn = (abfd->flags & DYNAMIC) != 0; + + /* ref_dynamic_nonweak and dynamic_def flags track actual undefined + syms and defined syms in dynamic libraries respectively. + ref_dynamic on the other hand can be set for a symbol defined in + a dynamic library, and def_dynamic may not be set; When the + definition in a dynamic lib is overridden by a definition in the + executable use of the symbol in the dynamic lib becomes a + reference to the executable symbol. */ + if (newdyn) + { + if (bfd_is_und_section (sec)) + { + if (bind != STB_WEAK) + { + h->ref_dynamic_nonweak = 1; + hi->ref_dynamic_nonweak = 1; + } + } + else + { + h->dynamic_def = 1; + hi->dynamic_def = 1; + } + } + /* If we just created the symbol, mark it as being an ELF symbol. Other than that, there is nothing to do--there is no merge issue with a newly defined symbol--so we just return. */ @@ -1012,6 +1046,8 @@ _bfd_elf_merge_symbol (bfd *abfd, newweak = bind == STB_WEAK; oldweak = (h->root.type == bfd_link_hash_defweak || h->root.type == bfd_link_hash_undefweak); + if (pold_weak) + *pold_weak = oldweak; /* In cases involving weak versioned symbols, we may wind up trying to merge a symbol with itself. Catch that here, to avoid the @@ -1025,11 +1061,6 @@ _bfd_elf_merge_symbol (bfd *abfd, || !h->def_regular)) return TRUE; - /* NEWDYN and OLDDYN indicate whether the new or old symbol, - respectively, is from a dynamic object. */ - - newdyn = (abfd->flags & DYNAMIC) != 0; - olddyn = FALSE; if (oldbfd != NULL) olddyn = (oldbfd->flags & DYNAMIC) != 0; @@ -1133,28 +1164,6 @@ _bfd_elf_merge_symbol (bfd *abfd, return FALSE; } - /* We need to remember if a symbol has a definition in a dynamic - object or is weak in all dynamic objects. Internal and hidden - visibility will make it unavailable to dynamic objects. */ - if (newdyn && !h->dynamic_def) - { - if (!bfd_is_und_section (sec)) - h->dynamic_def = 1; - else - { - /* Check if this symbol is weak in all dynamic objects. If it - is the first time we see it in a dynamic object, we mark - if it is weak. Otherwise, we clear it. */ - if (!h->ref_dynamic) - { - if (bind == STB_WEAK) - h->dynamic_weak = 1; - } - else if (bind != STB_WEAK) - h->dynamic_weak = 0; - } - } - /* If the old symbol has non-default visibility, we ignore the new definition from a dynamic object. */ if (newdyn @@ -1164,6 +1173,7 @@ _bfd_elf_merge_symbol (bfd *abfd, *skip = TRUE; /* Make sure this symbol is dynamic. */ h->ref_dynamic = 1; + hi->ref_dynamic = 1; /* A protected symbol has external availability. Make sure it is recorded as dynamic. @@ -1193,38 +1203,39 @@ _bfd_elf_merge_symbol (bfd *abfd, vh->root.type = h->root.type; h->root.type = bfd_link_hash_indirect; (*bed->elf_backend_copy_indirect_symbol) (info, vh, h); - /* Protected symbols will override the dynamic definition - with default version. */ - if (ELF_ST_VISIBILITY (sym->st_other) == STV_PROTECTED) + + h->root.u.i.link = (struct bfd_link_hash_entry *) vh; + if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED) { - h->root.u.i.link = (struct bfd_link_hash_entry *) vh; - vh->dynamic_def = 1; - vh->ref_dynamic = 1; + /* If the new symbol is hidden or internal, completely undo + any dynamic link state. */ + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + h->forced_local = 0; + h->ref_dynamic = 0; } else - { - h->root.type = vh->root.type; - vh->ref_dynamic = 0; - /* We have to hide it here since it was made dynamic - global with extra bits when the symbol info was - copied from the old dynamic definition. */ - (*bed->elf_backend_hide_symbol) (info, vh, TRUE); - } + h->ref_dynamic = 1; + + h->def_dynamic = 0; + /* FIXME: Should we check type and size for protected symbol? */ + h->size = 0; + h->type = 0; + h = vh; } else h = *sym_hash; } - if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root) - && bfd_is_und_section (sec)) + /* If the old symbol was undefined before, then it will still be + on the undefs list. If the new symbol is undefined or + common, we can't make it bfd_link_hash_new here, because new + undefined or common symbols will be added to the undefs list + by _bfd_generic_link_add_one_symbol. Symbols may not be + added twice to the undefs list. Also, if the new symbol is + undefweak then we don't want to lose the strong undef. */ + if (h->root.u.undef.next || info->hash->undefs_tail == &h->root) { - /* If the new symbol is undefined and the old symbol was - also undefined before, we need to make sure - _bfd_generic_link_add_one_symbol doesn't mess - up the linker hash table undefs list. Since the old - definition came from a dynamic object, it is still on the - undefs list. */ h->root.type = bfd_link_hash_undefined; h->root.u.undef.abfd = abfd; } @@ -1234,20 +1245,23 @@ _bfd_elf_merge_symbol (bfd *abfd, h->root.u.undef.abfd = NULL; } - if (h->def_dynamic) + if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED) { - h->def_dynamic = 0; - h->ref_dynamic = 1; + /* If the new symbol is hidden or internal, completely undo + any dynamic link state. */ + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + h->forced_local = 0; + h->ref_dynamic = 0; } + else + h->ref_dynamic = 1; + h->def_dynamic = 0; /* FIXME: Should we check type and size for protected symbol? */ h->size = 0; h->type = 0; return TRUE; } - if (bind == STB_GNU_UNIQUE) - h->unique_global = 1; - /* If a new weak symbol definition comes from a regular file and the old symbol comes from a dynamic library, we treat the new one as strong. Similarly, an old weak symbol definition from a regular @@ -1636,7 +1650,7 @@ _bfd_elf_add_default_symbol (bfd *abfd, size_change_ok = FALSE; sec = *psec; if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value, - NULL, &hi, &skip, &override, + NULL, NULL, &hi, &skip, &override, &type_change_ok, &size_change_ok)) return FALSE; @@ -1717,6 +1731,7 @@ _bfd_elf_add_default_symbol (bfd *abfd, if (! dynamic) { if (! info->executable + || hi->def_dynamic || hi->ref_dynamic) *dynsym = TRUE; } @@ -1744,7 +1759,7 @@ nondefault: size_change_ok = FALSE; sec = *psec; if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value, - NULL, &hi, &skip, &override, + NULL, NULL, &hi, &skip, &override, &type_change_ok, &size_change_ok)) return FALSE; @@ -2510,23 +2525,21 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, over to the real definition. */ if (h->u.weakdef != NULL) { - struct elf_link_hash_entry *weakdef; - - weakdef = h->u.weakdef; - while (h->root.type == bfd_link_hash_indirect) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - BFD_ASSERT (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak); - BFD_ASSERT (weakdef->def_dynamic); - /* If the real definition is defined by a regular object file, don't do anything special. See the longer description in _bfd_elf_adjust_dynamic_symbol, below. */ - if (weakdef->def_regular) + if (h->u.weakdef->def_regular) h->u.weakdef = NULL; else { + struct elf_link_hash_entry *weakdef = h->u.weakdef; + + while (h->root.type == bfd_link_hash_indirect) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak); + BFD_ASSERT (weakdef->def_dynamic); BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined || weakdef->root.type == bfd_link_hash_defweak); (*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef, h); @@ -2708,7 +2721,7 @@ _bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *data) if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) && ((sec = h->root.u.def.section)->flags & SEC_MERGE) - && sec->sec_info_type == ELF_INFO_TYPE_MERGE) + && sec->sec_info_type == SEC_INFO_TYPE_MERGE) { bfd *output_bfd = (bfd *) data; @@ -3031,7 +3044,7 @@ _bfd_elf_add_dynamic_entry (struct bfd_link_info *info, return FALSE; bed = get_elf_backend_data (hash_table->dynobj); - s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic"); + s = bfd_get_linker_section (hash_table->dynobj, ".dynamic"); BFD_ASSERT (s != NULL); newsize = s->size + bed->s->sizeof_dyn; @@ -3060,26 +3073,24 @@ elf_add_dt_needed_tag (bfd *abfd, bfd_boolean do_it) { struct elf_link_hash_table *hash_table; - bfd_size_type oldsize; bfd_size_type strindex; if (!_bfd_elf_link_create_dynstrtab (abfd, info)) return -1; hash_table = elf_hash_table (info); - oldsize = _bfd_elf_strtab_size (hash_table->dynstr); strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE); if (strindex == (bfd_size_type) -1) return -1; - if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr)) + if (_bfd_elf_strtab_refcount (hash_table->dynstr, strindex) != 1) { asection *sdyn; const struct elf_backend_data *bed; bfd_byte *extdyn; bed = get_elf_backend_data (hash_table->dynobj); - sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic"); + sdyn = bfd_get_linker_section (hash_table->dynobj, ".dynamic"); if (sdyn != NULL) for (extdyn = sdyn->contents; extdyn < sdyn->contents + sdyn->size; @@ -3122,7 +3133,7 @@ on_needed_list (const char *soname, struct bfd_link_needed_list *needed) return FALSE; } -/* Sort symbol by value and section. */ +/* Sort symbol by value, section, and size. */ static int elf_sort_symbol (const void *arg1, const void *arg2) { @@ -3141,7 +3152,8 @@ elf_sort_symbol (const void *arg1, const void *arg2) if (sdiff != 0) return sdiff > 0 ? 1 : -1; } - return 0; + vdiff = h1->size - h2->size; + return vdiff == 0 ? 0 : vdiff > 0 ? 1 : -1; } /* This function is used to adjust offsets into .dynstr for @@ -3176,7 +3188,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info) size = _bfd_elf_strtab_size (dynstr); bed = get_elf_backend_data (dynobj); - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); BFD_ASSERT (sdyn != NULL); /* Update all .dynamic entries referencing .dynstr strings. */ @@ -3225,7 +3237,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info) Elf_Internal_Verdef def; Elf_Internal_Verdaux defaux; - s = bfd_get_section_by_name (dynobj, ".gnu.version_d"); + s = bfd_get_linker_section (dynobj, ".gnu.version_d"); p = s->contents; do { @@ -3257,7 +3269,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info) Elf_Internal_Verneed need; Elf_Internal_Vernaux needaux; - s = bfd_get_section_by_name (dynobj, ".gnu.version_r"); + s = bfd_get_linker_section (dynobj, ".gnu.version_r"); p = s->contents; do { @@ -3353,6 +3365,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) struct bfd_link_hash_entry *old_undefs = NULL; struct bfd_link_hash_entry *old_undefs_tail = NULL; long old_dynsymcount = 0; + bfd_size_type old_dynstr_size = 0; size_t tabsize = 0; size_t hashsize = 0; @@ -3499,7 +3512,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) /* ld --just-symbols and dynamic objects don't mix very well. ld shouldn't allow it. */ if ((s = abfd->sections) != NULL - && s->sec_info_type == ELF_INFO_TYPE_JUST_SYMS) + && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) abort (); /* If this dynamic lib was specified on the command line with @@ -3680,7 +3693,7 @@ error_free_dyn: return TRUE; /* Save the DT_AUDIT entry for the linker emulation code. */ - elf_dt_audit (abfd) = audit; + elf_dt_audit (abfd) = audit; } /* If this is a dynamic object, we always link against the .dynsym @@ -3802,6 +3815,7 @@ error_free_dyn: old_size = htab->root.table.size; old_count = htab->root.table.count; old_dynsymcount = htab->dynsymcount; + old_dynstr_size = _bfd_elf_strtab_size (htab->dynstr); for (i = 0; i < htab->root.table.size; i++) { @@ -3834,10 +3848,13 @@ error_free_dyn: flagword flags; const char *name; struct elf_link_hash_entry *h; + struct elf_link_hash_entry *hi; bfd_boolean definition; bfd_boolean size_change_ok; bfd_boolean type_change_ok; bfd_boolean new_weakdef; + bfd_boolean new_weak; + bfd_boolean old_weak; bfd_boolean override; bfd_boolean common; unsigned int old_alignment; @@ -3896,7 +3913,7 @@ error_free_dyn: sec = bfd_section_from_elf_index (abfd, isym->st_shndx); if (sec == NULL) sec = bfd_abs_section_ptr; - else if (elf_discarded_section (sec)) + else if (discarded_section (sec)) { /* Symbols from discarded section are undefined. We keep its visibility. */ @@ -3970,6 +3987,7 @@ error_free_dyn: size_change_ok = FALSE; type_change_ok = bed->type_change_ok; + old_weak = FALSE; old_alignment = 0; old_bfd = NULL; new_sec = sec; @@ -3981,19 +3999,21 @@ error_free_dyn: bfd_boolean skip; /* If this is a definition of a symbol which was previously - referenced in a non-weak manner then make a note of the bfd - that contained the reference. This is used if we need to - refer to the source of the reference later on. */ + referenced, then make a note of the bfd that contained the + reference. This is used if we need to refer to the source + of the reference later on. */ if (! bfd_is_und_section (sec)) { - h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE); + h = elf_link_hash_lookup (elf_hash_table (info), name, + FALSE, FALSE, FALSE); if (h != NULL - && h->root.type == bfd_link_hash_undefined + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) && h->root.u.undef.abfd) undef_bfd = h->root.u.undef.abfd; } - + if (ever == NULL) { if (info->default_imported_symver) @@ -4102,20 +4122,21 @@ error_free_dyn: } /* If necessary, make a second attempt to locate the bfd - containing an unresolved, non-weak reference to the - current symbol. */ + containing an unresolved reference to the current symbol. */ if (! bfd_is_und_section (sec) && undef_bfd == NULL) { - h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE); + h = elf_link_hash_lookup (elf_hash_table (info), name, + FALSE, FALSE, FALSE); if (h != NULL - && h->root.type == bfd_link_hash_undefined + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) && h->root.u.undef.abfd) undef_bfd = h->root.u.undef.abfd; } if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, - &value, &old_alignment, + &value, &old_weak, &old_alignment, sym_hash, &skip, &override, &type_change_ok, &size_change_ok)) goto error_free_vers; @@ -4154,7 +4175,6 @@ error_free_dyn: } if (elf_tdata (abfd)->verdef != NULL - && ! override && vernum > 1 && definition) h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1]; @@ -4166,18 +4186,20 @@ error_free_dyn: goto error_free_vers; h = *sym_hash; + /* We need to make sure that indirect symbol dynamic flags are + updated. */ + hi = h; while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; *sym_hash = h; - if (is_elf_hash_table (htab)) - h->unique_global = (flags & BSF_GNU_UNIQUE) != 0; + new_weak = (flags & BSF_WEAK) != 0; new_weakdef = FALSE; if (dynamic && definition - && (flags & BSF_WEAK) != 0 + && new_weak && !bed->is_function_type (ELF_ST_TYPE (isym->st_info)) && is_elf_hash_table (htab) && h->u.weakdef == NULL) @@ -4306,7 +4328,9 @@ error_free_dyn: h->size = h->root.u.c.size; if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE - && (definition || h->type == STT_NOTYPE)) + && ((definition && !new_weak) + || (old_weak && h->root.type == bfd_link_hash_common) + || h->type == STT_NOTYPE)) { unsigned int type = ELF_ST_TYPE (isym->st_info); @@ -4354,25 +4378,36 @@ error_free_dyn: h->ref_dynamic = 1; } } - if (! info->executable - || h->def_dynamic - || h->ref_dynamic) + + /* If the indirect symbol has been forced local, don't + make the real symbol dynamic. */ + if ((h == hi || !hi->forced_local) + && (! info->executable + || h->def_dynamic + || h->ref_dynamic)) dynsym = TRUE; } else { if (! definition) - h->ref_dynamic = 1; + { + h->ref_dynamic = 1; + hi->ref_dynamic = 1; + } else { h->def_dynamic = 1; - h->dynamic_def = 1; + hi->def_dynamic = 1; } - if (h->def_regular - || h->ref_regular - || (h->u.weakdef != NULL - && ! new_weakdef - && h->u.weakdef->dynindx != -1)) + + /* If the indirect symbol has been forced local, don't + make the real symbol dynamic. */ + if ((h == hi || !hi->forced_local) + && (h->def_regular + || h->ref_regular + || (h->u.weakdef != NULL + && ! new_weakdef + && h->u.weakdef->dynindx != -1))) dynsym = TRUE; } @@ -4385,7 +4420,10 @@ error_free_dyn: dynsym = FALSE; if (definition) - h->target_internal = isym->st_target_internal; + { + h->target_internal = isym->st_target_internal; + h->unique_global = (flags & BSF_GNU_UNIQUE) != 0; + } /* Check to see if we need to add an indirect symbol for the default name. */ @@ -4440,10 +4478,13 @@ error_free_dyn: break; } + /* Don't add DT_NEEDED for references from the dummy bfd. */ if (!add_needed && definition && ((dynsym - && h->ref_regular) + && h->ref_regular + && (undef_bfd == NULL + || (undef_bfd->flags & BFD_PLUGIN) == 0)) || (h->ref_dynamic && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0 && !on_needed_list (elf_dt_name (abfd), htab->needed)))) @@ -4511,6 +4552,7 @@ error_free_dyn: memcpy (sym_hash, old_hash, hashsize); htab->root.undefs = old_undefs; htab->root.undefs_tail = old_undefs_tail; + _bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size); for (i = 0; i < htab->root.table.size; i++) { struct bfd_hash_entry *p; @@ -4523,12 +4565,13 @@ error_free_dyn: h = (struct elf_link_hash_entry *) p; if (h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - if (h->dynindx >= old_dynsymcount) + if (h->dynindx >= old_dynsymcount + && h->dynstr_index < old_dynstr_size) _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index); /* Preserve the maximum alignment and size for common symbols even if this dynamic lib isn't on DT_NEEDED - since it can still be loaded at the run-time by another + since it can still be loaded at run time by another dynamic lib. */ if (h->root.type == bfd_link_hash_common) { @@ -4547,8 +4590,9 @@ error_free_dyn: { memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize); old_ent = (char *) old_ent + htab->root.table.entsize; + h = (struct elf_link_hash_entry *) h->root.u.i.link; } - else if (h->root.type == bfd_link_hash_common) + if (h->root.type == bfd_link_hash_common) { if (size > h->root.u.c.size) h->root.u.c.size = size; @@ -4686,7 +4730,6 @@ error_free_dyn: struct elf_link_hash_entry *hlook; asection *slook; bfd_vma vlook; - long ilook; size_t i, j, idx; hlook = weaks; @@ -4700,14 +4743,13 @@ error_free_dyn: slook = hlook->root.u.def.section; vlook = hlook->root.u.def.value; - ilook = -1; i = 0; j = sym_count; - while (i < j) + while (i != j) { bfd_signed_vma vdiff; idx = (i + j) / 2; - h = sorted_sym_hash [idx]; + h = sorted_sym_hash[idx]; vdiff = vlook - h->root.u.def.value; if (vdiff < 0) j = idx; @@ -4721,24 +4763,36 @@ error_free_dyn: else if (sdiff > 0) i = idx + 1; else - { - ilook = idx; - break; - } + break; } } /* We didn't find a value/section match. */ - if (ilook == -1) + if (i == j) continue; - for (i = ilook; i < sym_count; i++) + /* With multiple aliases, or when the weak symbol is already + strongly defined, we have multiple matching symbols and + the binary search above may land on any of them. Step + one past the matching symbol(s). */ + while (++idx != j) { - h = sorted_sym_hash [i]; + h = sorted_sym_hash[idx]; + if (h->root.u.def.section != slook + || h->root.u.def.value != vlook) + break; + } + + /* Now look back over the aliases. Since we sorted by size + as well as value and section, we'll choose the one with + the largest size. */ + while (idx-- != i) + { + h = sorted_sym_hash[idx]; /* Stop if value or section doesn't match. */ - if (h->root.u.def.value != vlook - || h->root.u.def.section != slook) + if (h->root.u.def.section != slook + || h->root.u.def.value != vlook) break; else if (h != hlook) { @@ -4861,7 +4915,7 @@ error_free_dyn: &string_offset)) goto error_return; if (secdata->sec_info) - stab->sec_info_type = ELF_INFO_TYPE_STABS; + stab->sec_info_type = SEC_INFO_TYPE_STABS; } } } @@ -5502,6 +5556,65 @@ _bfd_elf_size_group_sections (struct bfd_link_info *info) return TRUE; } +/* Set a default stack segment size. The value in INFO wins. If it + is unset, LEGACY_SYMBOL's value is used, and if that symbol is + undefined it is initialized. */ + +bfd_boolean +bfd_elf_stack_segment_size (bfd *output_bfd, + struct bfd_link_info *info, + const char *legacy_symbol, + bfd_vma default_size) +{ + struct elf_link_hash_entry *h = NULL; + + /* Look for legacy symbol. */ + if (legacy_symbol) + h = elf_link_hash_lookup (elf_hash_table (info), legacy_symbol, + FALSE, FALSE, FALSE); + if (h && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->def_regular + && (h->type == STT_NOTYPE || h->type == STT_OBJECT)) + { + /* The symbol has no type if specified on the command line. */ + h->type = STT_OBJECT; + if (info->stacksize) + (*_bfd_error_handler) (_("%B: stack size specified and %s set"), + output_bfd, legacy_symbol); + else if (h->root.u.def.section != bfd_abs_section_ptr) + (*_bfd_error_handler) (_("%B: %s not absolute"), + output_bfd, legacy_symbol); + else + info->stacksize = h->root.u.def.value; + } + + if (!info->stacksize) + /* If the user didn't set a size, or explicitly inhibit the + size, set it now. */ + info->stacksize = default_size; + + /* Provide the legacy symbol, if it is referenced. */ + if (h && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak)) + { + struct bfd_link_hash_entry *bh = NULL; + + if (!(_bfd_generic_link_add_one_symbol + (info, output_bfd, legacy_symbol, + BSF_GLOBAL, bfd_abs_section_ptr, + info->stacksize >= 0 ? info->stacksize : 0, + NULL, FALSE, get_elf_backend_data (output_bfd)->collect, &bh))) + return FALSE; + + h = (struct elf_link_hash_entry *) bh; + h->def_regular = 1; + h->type = STT_OBJECT; + } + + return TRUE; +} + /* Set up the sizes and contents of the ELF dynamic sections. This is called by the ELF linker emulation before_allocation routine. We must set the sizes of the sections before the linker sets the @@ -5531,10 +5644,30 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, return TRUE; bed = get_elf_backend_data (output_bfd); + + /* Any syms created from now on start with -1 in + got.refcount/offset and plt.refcount/offset. */ + elf_hash_table (info)->init_got_refcount + = elf_hash_table (info)->init_got_offset; + elf_hash_table (info)->init_plt_refcount + = elf_hash_table (info)->init_plt_offset; + + if (info->relocatable + && !_bfd_elf_size_group_sections (info)) + return FALSE; + + /* The backend may have to create some sections regardless of whether + we're dynamic or not. */ + if (bed->elf_backend_always_size_sections + && ! (*bed->elf_backend_always_size_sections) (output_bfd, info)) + return FALSE; + + /* Determine any GNU_STACK segment requirements, after the backend + has had a chance to set a default segment size. */ if (info->execstack) - elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X; + elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X; else if (info->noexecstack) - elf_tdata (output_bfd)->stack_flags = PF_R | PF_W; + elf_stack_flags (output_bfd) = PF_R | PF_W; else { bfd *inputobj; @@ -5560,43 +5693,16 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, else if (bed->default_execstack) exec = PF_X; } - if (notesec) - { - elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec; - if (exec && info->relocatable - && notesec->output_section != bfd_abs_section_ptr) - notesec->output_section->flags |= SEC_CODE; - } + if (notesec || info->stacksize > 0) + elf_stack_flags (output_bfd) = PF_R | PF_W | exec; + if (notesec && exec && info->relocatable + && notesec->output_section != bfd_abs_section_ptr) + notesec->output_section->flags |= SEC_CODE; } - /* Any syms created from now on start with -1 in - got.refcount/offset and plt.refcount/offset. */ - elf_hash_table (info)->init_got_refcount - = elf_hash_table (info)->init_got_offset; - elf_hash_table (info)->init_plt_refcount - = elf_hash_table (info)->init_plt_offset; - - if (info->relocatable - && !_bfd_elf_size_group_sections (info)) - return FALSE; - - /* The backend may have to create some sections regardless of whether - we're dynamic or not. */ - if (bed->elf_backend_always_size_sections - && ! (*bed->elf_backend_always_size_sections) (output_bfd, info)) - return FALSE; - - if (! _bfd_elf_maybe_strip_eh_frame_hdr (info)) - return FALSE; - dynobj = elf_hash_table (info)->dynobj; - /* If there were no dynamic objects in the link, there is nothing to - do here. */ - if (dynobj == NULL) - return TRUE; - - if (elf_hash_table (info)->dynamic_sections_created) + if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) { struct elf_info_failed eif; struct elf_link_hash_entry *h; @@ -5606,7 +5712,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, asection *s; bfd_boolean all_defined; - *sinterpptr = bfd_get_section_by_name (dynobj, ".interp"); + *sinterpptr = bfd_get_linker_section (dynobj, ".interp"); BFD_ASSERT (*sinterpptr != NULL || !info->executable); if (soname != NULL) @@ -5628,19 +5734,16 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, if (rpath != NULL) { bfd_size_type indx; + bfd_vma tag; indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath, TRUE); - if (indx == (bfd_size_type) -1 - || !_bfd_elf_add_dynamic_entry (info, DT_RPATH, indx)) + if (indx == (bfd_size_type) -1) return FALSE; - if (info->new_dtags) - { - _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, indx); - if (!_bfd_elf_add_dynamic_entry (info, DT_RUNPATH, indx)) - return FALSE; - } + tag = info->new_dtags ? DT_RUNPATH : DT_RPATH; + if (!_bfd_elf_add_dynamic_entry (info, tag, indx)) + return FALSE; } if (filter_shlib != NULL) @@ -5874,7 +5977,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, return FALSE; } - dynstr = bfd_get_section_by_name (dynobj, ".dynstr"); + dynstr = bfd_get_linker_section (dynobj, ".dynstr"); /* If .dynstr is excluded from the link, we don't want any of these tags. Strictly, we should be checking each section individually; This quick check covers for the case where @@ -5899,18 +6002,22 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, /* The backend must work out the sizes of all the other dynamic sections. */ - if (bed->elf_backend_size_dynamic_sections + if (dynobj != NULL + && bed->elf_backend_size_dynamic_sections != NULL && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info)) return FALSE; - if (elf_hash_table (info)->dynamic_sections_created) + if (! _bfd_elf_maybe_strip_eh_frame_hdr (info)) + return FALSE; + + if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) { unsigned long section_sym_count; struct bfd_elf_version_tree *verdefs; asection *s; /* Set up the version definition section. */ - s = bfd_get_section_by_name (dynobj, ".gnu.version_d"); + s = bfd_get_linker_section (dynobj, ".gnu.version_d"); BFD_ASSERT (s != NULL); /* We may have created additional version definitions if we are @@ -6173,7 +6280,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, /* Work out the size of the version reference section. */ - s = bfd_get_section_by_name (dynobj, ".gnu.version_r"); + s = bfd_get_linker_section (dynobj, ".gnu.version_r"); BFD_ASSERT (s != NULL); { struct elf_find_verdep_info sinfo; @@ -6285,7 +6392,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, || _bfd_elf_link_renumber_dynsyms (output_bfd, info, §ion_sym_count) == 0) { - s = bfd_get_section_by_name (dynobj, ".gnu.version"); + s = bfd_get_linker_section (dynobj, ".gnu.version"); s->flags |= SEC_EXCLUDE; } } @@ -6369,7 +6476,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) §ion_sym_count); /* Work out the size of the symbol version section. */ - s = bfd_get_section_by_name (dynobj, ".gnu.version"); + s = bfd_get_linker_section (dynobj, ".gnu.version"); BFD_ASSERT (s != NULL); if (dynsymcount != 0 && (s->flags & SEC_EXCLUDE) == 0) @@ -6389,7 +6496,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) the final symbol table, because until then we do not know the correct value to give the symbols. We built the .dynstr section as we went along in elf_link_add_object_symbols. */ - s = bfd_get_section_by_name (dynobj, ".dynsym"); + s = bfd_get_linker_section (dynobj, ".dynsym"); BFD_ASSERT (s != NULL); s->size = dynsymcount * bed->s->sizeof_sym; @@ -6447,7 +6554,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) elf_hash_table (info)->bucketcount = bucketcount; - s = bfd_get_section_by_name (dynobj, ".hash"); + s = bfd_get_linker_section (dynobj, ".hash"); BFD_ASSERT (s != NULL); hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize; s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size); @@ -6501,7 +6608,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) return FALSE; } - s = bfd_get_section_by_name (dynobj, ".gnu.hash"); + s = bfd_get_linker_section (dynobj, ".gnu.hash"); BFD_ASSERT (s != NULL); if (cinfo.nsyms == 0) @@ -6629,7 +6736,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) } } - s = bfd_get_section_by_name (dynobj, ".dynstr"); + s = bfd_get_linker_section (dynobj, ".dynstr"); BFD_ASSERT (s != NULL); elf_finalize_dynstr (output_bfd, info); @@ -6644,25 +6751,14 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) return TRUE; } -/* Indicate that we are only retrieving symbol values from this - section. */ - -void -_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info) -{ - if (is_elf_hash_table (info->hash)) - sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS; - _bfd_generic_link_just_syms (sec, info); -} - /* Make sure sec_info_type is cleared if sec_info is cleared too. */ static void merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) { - BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE); - sec->sec_info_type = ELF_INFO_TYPE_NONE; + BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_MERGE); + sec->sec_info_type = SEC_INFO_TYPE_NONE; } /* Finish SHF_MERGE section merging. */ @@ -6690,7 +6786,7 @@ _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info) sec, &secdata->sec_info)) return FALSE; else if (secdata->sec_info) - sec->sec_info_type = ELF_INFO_TYPE_MERGE; + sec->sec_info_type = SEC_INFO_TYPE_MERGE; } if (elf_hash_table (info)->merge_info != NULL) @@ -6816,7 +6912,8 @@ _bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info, } } -/* Initialize an ELF linker hash table. */ +/* Initialize an ELF linker hash table. *TABLE has been zeroed by our + caller. */ bfd_boolean _bfd_elf_link_hash_table_init @@ -6831,7 +6928,6 @@ _bfd_elf_link_hash_table_init bfd_boolean ret; int can_refcount = get_elf_backend_data (abfd)->can_refcount; - memset (table, 0, sizeof * table); table->init_got_refcount.refcount = can_refcount - 1; table->init_plt_refcount.refcount = can_refcount - 1; table->init_got_offset.offset = -(bfd_vma) 1; @@ -6855,7 +6951,7 @@ _bfd_elf_link_hash_table_create (bfd *abfd) struct elf_link_hash_table *ret; bfd_size_type amt = sizeof (struct elf_link_hash_table); - ret = (struct elf_link_hash_table *) bfd_malloc (amt); + ret = (struct elf_link_hash_table *) bfd_zmalloc (amt); if (ret == NULL) return NULL; @@ -6870,6 +6966,18 @@ _bfd_elf_link_hash_table_create (bfd *abfd) return &ret->root; } +/* Destroy an ELF linker hash table. */ + +void +_bfd_elf_link_hash_table_free (struct bfd_link_hash_table *hash) +{ + struct elf_link_hash_table *htab = (struct elf_link_hash_table *) hash; + if (htab->dynstr != NULL) + _bfd_elf_strtab_free (htab->dynstr); + _bfd_merge_sections_free (htab->merge_info); + _bfd_generic_link_hash_table_free (hash); +} + /* This is a hook for the ELF emulation code in the generic linker to tell the backend linker what file name to use for the DT_NEEDED entry for a dynamic object. */ @@ -7413,6 +7521,8 @@ struct elf_final_link_info size_t symbuf_size; /* And same for symshndxbuf. */ size_t shndxbuf_size; + /* Number of STT_FILE syms seen. */ + size_t filesym_count; }; /* This struct is used to pass information to elf_link_output_extsym. */ @@ -7421,7 +7531,9 @@ struct elf_outext_info { bfd_boolean failed; bfd_boolean localsyms; - struct elf_final_link_info *finfo; + bfd_boolean need_second_pass; + bfd_boolean second_pass; + struct elf_final_link_info *flinfo; }; @@ -7498,7 +7610,7 @@ set_symbol_value (bfd *bfd_with_globals, static bfd_boolean resolve_symbol (const char *name, bfd *input_bfd, - struct elf_final_link_info *finfo, + struct elf_final_link_info *flinfo, bfd_vma *result, Elf_Internal_Sym *isymbuf, size_t locsymcount) @@ -7527,7 +7639,7 @@ resolve_symbol (const char *name, #endif if (candidate && strcmp (candidate, name) == 0) { - asection *sec = finfo->sections [i]; + asection *sec = flinfo->sections [i]; *result = _bfd_elf_rel_local_sym (input_bfd, sym, &sec, 0); *result += sec->output_offset + sec->output_section->vma; @@ -7540,7 +7652,7 @@ resolve_symbol (const char *name, } /* Hmm, haven't found it yet. perhaps it is a global. */ - global_entry = bfd_link_hash_lookup (finfo->info->hash, name, + global_entry = bfd_link_hash_lookup (flinfo->info->hash, name, FALSE, FALSE, TRUE); if (!global_entry) return FALSE; @@ -7609,7 +7721,7 @@ static bfd_boolean eval_symbol (bfd_vma *result, const char **symp, bfd *input_bfd, - struct elf_final_link_info *finfo, + struct elf_final_link_info *flinfo, bfd_vma dot, Elf_Internal_Sym *isymbuf, size_t locsymcount, @@ -7669,8 +7781,8 @@ eval_symbol (bfd_vma *result, if (symbol_is_section) { - if (!resolve_section (symbuf, finfo->output_bfd->sections, result) - && !resolve_symbol (symbuf, input_bfd, finfo, result, + if (!resolve_section (symbuf, flinfo->output_bfd->sections, result) + && !resolve_symbol (symbuf, input_bfd, flinfo, result, isymbuf, locsymcount)) { undefined_reference ("section", symbuf); @@ -7679,9 +7791,9 @@ eval_symbol (bfd_vma *result, } else { - if (!resolve_symbol (symbuf, input_bfd, finfo, result, + if (!resolve_symbol (symbuf, input_bfd, flinfo, result, isymbuf, locsymcount) - && !resolve_section (symbuf, finfo->output_bfd->sections, + && !resolve_section (symbuf, flinfo->output_bfd->sections, result)) { undefined_reference ("symbol", symbuf); @@ -7700,7 +7812,7 @@ eval_symbol (bfd_vma *result, if (*sym == ':') \ ++sym; \ *symp = sym; \ - if (!eval_symbol (&a, symp, input_bfd, finfo, dot, \ + if (!eval_symbol (&a, symp, input_bfd, flinfo, dot, \ isymbuf, locsymcount, signed_p)) \ return FALSE; \ if (signed_p) \ @@ -7717,11 +7829,11 @@ eval_symbol (bfd_vma *result, if (*sym == ':') \ ++sym; \ *symp = sym; \ - if (!eval_symbol (&a, symp, input_bfd, finfo, dot, \ + if (!eval_symbol (&a, symp, input_bfd, flinfo, dot, \ isymbuf, locsymcount, signed_p)) \ return FALSE; \ ++*symp; \ - if (!eval_symbol (&b, symp, input_bfd, finfo, dot, \ + if (!eval_symbol (&b, symp, input_bfd, flinfo, dot, \ isymbuf, locsymcount, signed_p)) \ return FALSE; \ if (signed_p) \ @@ -7803,31 +7915,49 @@ get_value (bfd_vma size, bfd *input_bfd, bfd_byte *location) { + int shift; bfd_vma x = 0; + /* Sanity checks. */ + BFD_ASSERT (chunksz <= sizeof (x) + && size >= chunksz + && chunksz != 0 + && (size % chunksz) == 0 + && input_bfd != NULL + && location != NULL); + + if (chunksz == sizeof (x)) + { + BFD_ASSERT (size == chunksz); + + /* Make sure that we do not perform an undefined shift operation. + We know that size == chunksz so there will only be one iteration + of the loop below. */ + shift = 0; + } + else + shift = 8 * chunksz; + for (; size; size -= chunksz, location += chunksz) { switch (chunksz) { - default: - case 0: - abort (); case 1: - x = (x << (8 * chunksz)) | bfd_get_8 (input_bfd, location); + x = (x << shift) | bfd_get_8 (input_bfd, location); break; case 2: - x = (x << (8 * chunksz)) | bfd_get_16 (input_bfd, location); + x = (x << shift) | bfd_get_16 (input_bfd, location); break; case 4: - x = (x << (8 * chunksz)) | bfd_get_32 (input_bfd, location); + x = (x << shift) | bfd_get_32 (input_bfd, location); break; - case 8: #ifdef BFD64 - x = (x << (8 * chunksz)) | bfd_get_64 (input_bfd, location); -#else - abort (); -#endif + case 8: + x = (x << shift) | bfd_get_64 (input_bfd, location); break; +#endif + default: + abort (); } } return x; @@ -8319,24 +8449,24 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) /* Flush the output symbols to the file. */ static bfd_boolean -elf_link_flush_output_syms (struct elf_final_link_info *finfo, +elf_link_flush_output_syms (struct elf_final_link_info *flinfo, const struct elf_backend_data *bed) { - if (finfo->symbuf_count > 0) + if (flinfo->symbuf_count > 0) { Elf_Internal_Shdr *hdr; file_ptr pos; bfd_size_type amt; - hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr; + hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr; pos = hdr->sh_offset + hdr->sh_size; - amt = finfo->symbuf_count * bed->s->sizeof_sym; - if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0 - || bfd_bwrite (finfo->symbuf, amt, finfo->output_bfd) != amt) + amt = flinfo->symbuf_count * bed->s->sizeof_sym; + if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) != 0 + || bfd_bwrite (flinfo->symbuf, amt, flinfo->output_bfd) != amt) return FALSE; hdr->sh_size += amt; - finfo->symbuf_count = 0; + flinfo->symbuf_count = 0; } return TRUE; @@ -8345,7 +8475,7 @@ elf_link_flush_output_syms (struct elf_final_link_info *finfo, /* Add a symbol to the output symbol table. */ static int -elf_link_output_sym (struct elf_final_link_info *finfo, +elf_link_output_sym (struct elf_final_link_info *flinfo, const char *name, Elf_Internal_Sym *elfsym, asection *input_sec, @@ -8358,11 +8488,11 @@ elf_link_output_sym (struct elf_final_link_info *finfo, struct elf_link_hash_entry *); const struct elf_backend_data *bed; - bed = get_elf_backend_data (finfo->output_bfd); + bed = get_elf_backend_data (flinfo->output_bfd); output_symbol_hook = bed->elf_backend_link_output_symbol_hook; if (output_symbol_hook != NULL) { - int ret = (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h); + int ret = (*output_symbol_hook) (flinfo->info, name, elfsym, input_sec, h); if (ret != 1) return ret; } @@ -8373,41 +8503,41 @@ elf_link_output_sym (struct elf_final_link_info *finfo, elfsym->st_name = 0; else { - elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab, + elfsym->st_name = (unsigned long) _bfd_stringtab_add (flinfo->symstrtab, name, TRUE, FALSE); if (elfsym->st_name == (unsigned long) -1) return 0; } - if (finfo->symbuf_count >= finfo->symbuf_size) + if (flinfo->symbuf_count >= flinfo->symbuf_size) { - if (! elf_link_flush_output_syms (finfo, bed)) + if (! elf_link_flush_output_syms (flinfo, bed)) return 0; } - dest = finfo->symbuf + finfo->symbuf_count * bed->s->sizeof_sym; - destshndx = finfo->symshndxbuf; + dest = flinfo->symbuf + flinfo->symbuf_count * bed->s->sizeof_sym; + destshndx = flinfo->symshndxbuf; if (destshndx != NULL) { - if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size) + if (bfd_get_symcount (flinfo->output_bfd) >= flinfo->shndxbuf_size) { bfd_size_type amt; - amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx); + amt = flinfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx); destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx, amt * 2); if (destshndx == NULL) return 0; - finfo->symshndxbuf = destshndx; + flinfo->symshndxbuf = destshndx; memset ((char *) destshndx + amt, 0, amt); - finfo->shndxbuf_size *= 2; + flinfo->shndxbuf_size *= 2; } - destshndx += bfd_get_symcount (finfo->output_bfd); + destshndx += bfd_get_symcount (flinfo->output_bfd); } - bed->s->swap_symbol_out (finfo->output_bfd, elfsym, dest, destshndx); - finfo->symbuf_count += 1; - bfd_get_symcount (finfo->output_bfd) += 1; + bed->s->swap_symbol_out (flinfo->output_bfd, elfsym, dest, destshndx); + flinfo->symbuf_count += 1; + bfd_get_symcount (flinfo->output_bfd) += 1; return 1; } @@ -8448,6 +8578,10 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info, if (!is_elf_hash_table (info->hash)) return FALSE; + /* Check indirect symbol. */ + while (h->root.type == bfd_link_hash_indirect) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + switch (h->root.type) { default: @@ -8595,7 +8729,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) { struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh; struct elf_outext_info *eoinfo = (struct elf_outext_info *) data; - struct elf_final_link_info *finfo = eoinfo->finfo; + struct elf_final_link_info *flinfo = eoinfo->flinfo; bfd_boolean strip; Elf_Internal_Sym sym; asection *input_sec; @@ -8615,6 +8749,11 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) { if (!h->forced_local) return TRUE; + if (eoinfo->second_pass + && !((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->root.u.def.section->output_section != NULL)) + return TRUE; } else { @@ -8622,7 +8761,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) return TRUE; } - bed = get_elf_backend_data (finfo->output_bfd); + bed = get_elf_backend_data (flinfo->output_bfd); if (h->root.type == bfd_link_hash_undefined) { @@ -8641,14 +8780,16 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) /* If we are reporting errors for this situation then do so now. */ if (!ignore_undef && h->ref_dynamic - && (!h->ref_regular || finfo->info->gc_sections) - && ! elf_link_check_versioned_symbol (finfo->info, bed, h) - && finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE) - { - if (! (finfo->info->callbacks->undefined_symbol - (finfo->info, h->root.root.string, - h->ref_regular ? NULL : h->root.u.undef.abfd, - NULL, 0, finfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR))) + && (!h->ref_regular || flinfo->info->gc_sections) + && !elf_link_check_versioned_symbol (flinfo->info, bed, h) + && flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE) + { + if (!(flinfo->info->callbacks->undefined_symbol + (flinfo->info, h->root.root.string, + h->ref_regular ? NULL : h->root.u.undef.abfd, + NULL, 0, + (flinfo->info->unresolved_syms_in_shared_libs + == RM_GENERATE_ERROR)))) { bfd_set_error (bfd_error_bad_value); eoinfo->failed = TRUE; @@ -8659,17 +8800,22 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) /* We should also warn if a forced local symbol is referenced from shared libraries. */ - if (!finfo->info->relocatable - && finfo->info->executable + if (!flinfo->info->relocatable + && flinfo->info->executable && h->forced_local && h->ref_dynamic && h->def_regular && !h->dynamic_def - && !h->dynamic_weak - && ! elf_link_check_versioned_symbol (finfo->info, bed, h)) + && h->ref_dynamic_nonweak + && !elf_link_check_versioned_symbol (flinfo->info, bed, h)) { bfd *def_bfd; const char *msg; + struct elf_link_hash_entry *hi = h; + + /* Check indirect symbol. */ + while (hi->root.type == bfd_link_hash_indirect) + hi = (struct elf_link_hash_entry *) hi->root.u.i.link; if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL) msg = _("%B: internal symbol `%s' in %B is referenced by DSO"); @@ -8677,10 +8823,10 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) msg = _("%B: hidden symbol `%s' in %B is referenced by DSO"); else msg = _("%B: local symbol `%s' in %B is referenced by DSO"); - def_bfd = finfo->output_bfd; - if (h->root.u.def.section != bfd_abs_section_ptr) - def_bfd = h->root.u.def.section->owner; - (*_bfd_error_handler) (msg, finfo->output_bfd, def_bfd, + def_bfd = flinfo->output_bfd; + if (hi->root.u.def.section != bfd_abs_section_ptr) + def_bfd = hi->root.u.def.section->owner; + (*_bfd_error_handler) (msg, flinfo->output_bfd, def_bfd, h->root.root.string); bfd_set_error (bfd_error_bad_value); eoinfo->failed = TRUE; @@ -8699,16 +8845,16 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) && !h->def_regular && !h->ref_regular) strip = TRUE; - else if (finfo->info->strip == strip_all) + else if (flinfo->info->strip == strip_all) strip = TRUE; - else if (finfo->info->strip == strip_some - && bfd_hash_lookup (finfo->info->keep_hash, + else if (flinfo->info->strip == strip_some + && bfd_hash_lookup (flinfo->info->keep_hash, h->root.root.string, FALSE, FALSE) == NULL) strip = TRUE; else if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) - && ((finfo->info->strip_discarded - && elf_discarded_section (h->root.u.def.section)) + && ((flinfo->info->strip_discarded + && discarded_section (h->root.u.def.section)) || (h->root.u.def.section->owner != NULL && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0))) strip = TRUE; @@ -8738,7 +8884,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) /* Turn off visibility on local symbol. */ sym.st_other &= ~ELF_ST_VISIBILITY (-1); } - else if (h->unique_global) + /* Set STB_GNU_UNIQUE only if symbol is defined in regular object. */ + else if (h->unique_global && h->def_regular) sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type); else if (h->root.type == bfd_link_hash_undefweak || h->root.type == bfd_link_hash_defweak) @@ -8767,14 +8914,27 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) input_sec = h->root.u.def.section; if (input_sec->output_section != NULL) { + if (eoinfo->localsyms && flinfo->filesym_count == 1) + { + bfd_boolean second_pass_sym + = (input_sec->owner == flinfo->output_bfd + || input_sec->owner == NULL + || (input_sec->flags & SEC_LINKER_CREATED) != 0 + || (input_sec->owner->flags & BFD_LINKER_CREATED) != 0); + + eoinfo->need_second_pass |= second_pass_sym; + if (eoinfo->second_pass != second_pass_sym) + return TRUE; + } + sym.st_shndx = - _bfd_elf_section_from_bfd_section (finfo->output_bfd, + _bfd_elf_section_from_bfd_section (flinfo->output_bfd, input_sec->output_section); if (sym.st_shndx == SHN_BAD) { (*_bfd_error_handler) (_("%B: could not find output section %A for input section %A"), - finfo->output_bfd, input_sec->output_section, input_sec); + flinfo->output_bfd, input_sec->output_section, input_sec); bfd_set_error (bfd_error_nonrepresentable_section); eoinfo->failed = TRUE; return FALSE; @@ -8784,18 +8944,18 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) but in nonrelocatable files they are virtual addresses. */ sym.st_value = h->root.u.def.value + input_sec->output_offset; - if (! finfo->info->relocatable) + if (!flinfo->info->relocatable) { sym.st_value += input_sec->output_section->vma; if (h->type == STT_TLS) { - asection *tls_sec = elf_hash_table (finfo->info)->tls_sec; + asection *tls_sec = elf_hash_table (flinfo->info)->tls_sec; if (tls_sec != NULL) sym.st_value -= tls_sec->vma; else { /* The TLS section may have been garbage collected. */ - BFD_ASSERT (finfo->info->gc_sections + BFD_ASSERT (flinfo->info->gc_sections && !input_sec->gc_mark); } } @@ -8834,17 +8994,17 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) STT_GNU_IFUNC symbol must go through PLT. */ if ((h->type == STT_GNU_IFUNC && h->def_regular - && !finfo->info->relocatable) + && !flinfo->info->relocatable) || ((h->dynindx != -1 || h->forced_local) - && ((finfo->info->shared + && ((flinfo->info->shared && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak)) || !h->forced_local) - && elf_hash_table (finfo->info)->dynamic_sections_created)) + && elf_hash_table (flinfo->info)->dynamic_sections_created)) { if (! ((*bed->elf_backend_finish_dynamic_symbol) - (finfo->output_bfd, finfo->info, h, &sym))) + (flinfo->output_bfd, flinfo->info, h, &sym))) { eoinfo->failed = TRUE; return FALSE; @@ -8887,7 +9047,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) /* If a non-weak symbol with non-default visibility is not defined locally, it is a fatal error. */ - if (! finfo->info->relocatable + if (!flinfo->info->relocatable && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT && ELF_ST_BIND (sym.st_info) != STB_WEAK && h->root.type == bfd_link_hash_undefined @@ -8901,7 +9061,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) msg = _("%B: internal symbol `%s' isn't defined"); else msg = _("%B: hidden symbol `%s' isn't defined"); - (*_bfd_error_handler) (msg, finfo->output_bfd, h->root.root.string); + (*_bfd_error_handler) (msg, flinfo->output_bfd, h->root.root.string); bfd_set_error (bfd_error_bad_value); eoinfo->failed = TRUE; return FALSE; @@ -8910,21 +9070,39 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) /* If this symbol should be put in the .dynsym section, then put it there now. We already know the symbol index. We also fill in the entry in the .hash section. */ - if (h->dynindx != -1 - && elf_hash_table (finfo->info)->dynamic_sections_created) + if (flinfo->dynsym_sec != NULL + && h->dynindx != -1 + && elf_hash_table (flinfo->info)->dynamic_sections_created) { bfd_byte *esym; + /* Since there is no version information in the dynamic string, + if there is no version info in symbol version section, we will + have a run-time problem. */ + if (h->verinfo.verdef == NULL) + { + char *p = strrchr (h->root.root.string, ELF_VER_CHR); + + if (p && p [1] != '\0') + { + (*_bfd_error_handler) + (_("%B: No symbol version section for versioned symbol `%s'"), + flinfo->output_bfd, h->root.root.string); + eoinfo->failed = TRUE; + return FALSE; + } + } + sym.st_name = h->dynstr_index; - esym = finfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym; - if (! check_dynsym (finfo->output_bfd, &sym)) + esym = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym; + if (!check_dynsym (flinfo->output_bfd, &sym)) { eoinfo->failed = TRUE; return FALSE; } - bed->s->swap_symbol_out (finfo->output_bfd, &sym, esym, 0); + bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0); - if (finfo->hash_sec != NULL) + if (flinfo->hash_sec != NULL) { size_t hash_entry_size; bfd_byte *bucketpos; @@ -8932,21 +9110,22 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) size_t bucketcount; size_t bucket; - bucketcount = elf_hash_table (finfo->info)->bucketcount; + bucketcount = elf_hash_table (flinfo->info)->bucketcount; bucket = h->u.elf_hash_value % bucketcount; hash_entry_size - = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; - bucketpos = ((bfd_byte *) finfo->hash_sec->contents + = elf_section_data (flinfo->hash_sec)->this_hdr.sh_entsize; + bucketpos = ((bfd_byte *) flinfo->hash_sec->contents + (bucket + 2) * hash_entry_size); - chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); - bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos); - bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, - ((bfd_byte *) finfo->hash_sec->contents + chain = bfd_get (8 * hash_entry_size, flinfo->output_bfd, bucketpos); + bfd_put (8 * hash_entry_size, flinfo->output_bfd, h->dynindx, + bucketpos); + bfd_put (8 * hash_entry_size, flinfo->output_bfd, chain, + ((bfd_byte *) flinfo->hash_sec->contents + (bucketcount + 2 + h->dynindx) * hash_entry_size)); } - if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL) + if (flinfo->symver_sec != NULL && flinfo->symver_sec->contents != NULL) { Elf_Internal_Versym iversym; Elf_External_Versym *eversym; @@ -8964,16 +9143,16 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) iversym.vs_vers = 1; else iversym.vs_vers = h->verinfo.vertree->vernum + 1; - if (finfo->info->create_default_symver) + if (flinfo->info->create_default_symver) iversym.vs_vers++; } if (h->hidden) iversym.vs_vers |= VERSYM_HIDDEN; - eversym = (Elf_External_Versym *) finfo->symver_sec->contents; + eversym = (Elf_External_Versym *) flinfo->symver_sec->contents; eversym += h->dynindx; - _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym); + _bfd_elf_swap_versym_out (flinfo->output_bfd, &iversym, eversym); } } @@ -8982,8 +9161,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) if (strip || (input_sec->flags & SEC_EXCLUDE) != 0) return TRUE; - indx = bfd_get_symcount (finfo->output_bfd); - ret = elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h); + indx = bfd_get_symcount (flinfo->output_bfd); + ret = elf_link_output_sym (flinfo, h->root.root.string, &sym, input_sec, h); if (ret == 0) { eoinfo->failed = TRUE; @@ -9007,8 +9186,8 @@ elf_section_ignore_discarded_relocs (asection *sec) switch (sec->sec_info_type) { - case ELF_INFO_TYPE_STABS: - case ELF_INFO_TYPE_EH_FRAME: + case SEC_INFO_TYPE_STABS: + case SEC_INFO_TYPE_EH_FRAME: return TRUE; default: break; @@ -9097,7 +9276,7 @@ _bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info) don't have to keep them in memory. */ static bfd_boolean -elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) +elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) { int (*relocate_section) (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, @@ -9117,8 +9296,9 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) bfd_size_type address_size; bfd_vma r_type_mask; int r_sym_shift; + bfd_boolean have_file_sym = FALSE; - output_bfd = finfo->output_bfd; + output_bfd = flinfo->output_bfd; bed = get_elf_backend_data (output_bfd); relocate_section = bed->elf_backend_relocate_section; @@ -9145,9 +9325,9 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) if (isymbuf == NULL && locsymcount != 0) { isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, - finfo->internal_syms, - finfo->external_syms, - finfo->locsym_shndx); + flinfo->internal_syms, + flinfo->external_syms, + flinfo->locsym_shndx); if (isymbuf == NULL) return FALSE; } @@ -9156,7 +9336,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) SEC_MERGE sections. Write out those local symbols we know are going into the output file. */ isymend = isymbuf + locsymcount; - for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections; + for (isym = isymbuf, pindex = flinfo->indices, ppsection = flinfo->sections; isym < isymend; isym++, pindex++, ppsection++) { @@ -9193,7 +9373,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) *ppsection = NULL; continue; } - else if (isec->sec_info_type == ELF_INFO_TYPE_MERGE + else if (isec->sec_info_type == SEC_INFO_TYPE_MERGE && ELF_ST_TYPE (isym->st_info) != STT_SECTION) isym->st_value = _bfd_merged_section_offset (output_bfd, &isec, @@ -9204,7 +9384,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) *ppsection = isec; /* Don't output the first, undefined, symbol. */ - if (ppsection == finfo->sections) + if (ppsection == flinfo->sections) continue; if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) @@ -9217,7 +9397,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) /* If we are stripping all symbols, we don't want to output this one. */ - if (finfo->info->strip == strip_all) + if (flinfo->info->strip == strip_all) continue; /* If we are discarding all local symbols, we don't want to @@ -9225,7 +9405,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) file, then some of the local symbols may be required by relocs; we output them below as we discover that they are needed. */ - if (finfo->info->discard == discard_all) + if (flinfo->info->discard == discard_all) continue; /* If this symbol is defined in a section which we are @@ -9243,15 +9423,38 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) return FALSE; /* See if we are discarding symbols with this name. */ - if ((finfo->info->strip == strip_some - && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE, FALSE) + if ((flinfo->info->strip == strip_some + && (bfd_hash_lookup (flinfo->info->keep_hash, name, FALSE, FALSE) == NULL)) - || (((finfo->info->discard == discard_sec_merge - && (isec->flags & SEC_MERGE) && ! finfo->info->relocatable) - || finfo->info->discard == discard_l) + || (((flinfo->info->discard == discard_sec_merge + && (isec->flags & SEC_MERGE) && !flinfo->info->relocatable) + || flinfo->info->discard == discard_l) && bfd_is_local_label_name (input_bfd, name))) continue; + if (ELF_ST_TYPE (isym->st_info) == STT_FILE) + { + have_file_sym = TRUE; + flinfo->filesym_count += 1; + } + if (!have_file_sym) + { + /* In the absence of debug info, bfd_find_nearest_line uses + FILE symbols to determine the source file for local + function symbols. Provide a FILE symbol here if input + files lack such, so that their symbols won't be + associated with a previous input file. It's not the + source file, but the best we can do. */ + have_file_sym = TRUE; + flinfo->filesym_count += 1; + memset (&osym, 0, sizeof (osym)); + osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + osym.st_shndx = SHN_ABS; + if (!elf_link_output_sym (flinfo, input_bfd->filename, &osym, + bfd_abs_section_ptr, NULL)) + return FALSE; + } + osym = *isym; /* Adjust the section index for the output file. */ @@ -9268,19 +9471,19 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) output_section. Any special sections must be set up to meet these requirements. */ osym.st_value += isec->output_offset; - if (! finfo->info->relocatable) + if (!flinfo->info->relocatable) { osym.st_value += isec->output_section->vma; if (ELF_ST_TYPE (osym.st_info) == STT_TLS) { /* STT_TLS symbols are relative to PT_TLS segment base. */ - BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL); - osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma; + BFD_ASSERT (elf_hash_table (flinfo->info)->tls_sec != NULL); + osym.st_value -= elf_hash_table (flinfo->info)->tls_sec->vma; } } indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_sym (finfo, name, &osym, isec, NULL); + ret = elf_link_output_sym (flinfo, name, &osym, isec, NULL); if (ret == 0) return FALSE; else if (ret == 1) @@ -9312,7 +9515,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) continue; } - if (finfo->info->relocatable + if (flinfo->info->relocatable && (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP) { /* Deal with the group signature symbol. */ @@ -9322,7 +9525,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) if (symndx >= locsymcount || (elf_bad_symtab (input_bfd) - && finfo->sections[symndx] == NULL)) + && flinfo->sections[symndx] == NULL)) { struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff]; while (h->root.type == bfd_link_hash_indirect @@ -9335,16 +9538,16 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION) { /* We'll use the output section target_index. */ - asection *sec = finfo->sections[symndx]->output_section; + asection *sec = flinfo->sections[symndx]->output_section; elf_section_data (osec)->this_hdr.sh_info = sec->target_index; } else { - if (finfo->indices[symndx] == -1) + if (flinfo->indices[symndx] == -1) { /* Otherwise output the local symbol now. */ Elf_Internal_Sym sym = isymbuf[symndx]; - asection *sec = finfo->sections[symndx]->output_section; + asection *sec = flinfo->sections[symndx]->output_section; const char *name; long indx; int ret; @@ -9363,16 +9566,16 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) sym.st_value += o->output_offset; indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_sym (finfo, name, &sym, o, NULL); + ret = elf_link_output_sym (flinfo, name, &sym, o, NULL); if (ret == 0) return FALSE; else if (ret == 1) - finfo->indices[symndx] = indx; + flinfo->indices[symndx] = indx; else abort (); } elf_section_data (osec)->this_hdr.sh_info - = finfo->indices[symndx]; + = flinfo->indices[symndx]; } } @@ -9395,7 +9598,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) contents = elf_section_data (o)->this_hdr.contents; else { - contents = finfo->contents; + contents = flinfo->contents; if (! bfd_get_full_section_contents (input_bfd, o, &contents)) return FALSE; } @@ -9409,8 +9612,8 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) /* Get the swapped relocs. */ internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, o, finfo->external_relocs, - finfo->internal_relocs, FALSE); + = _bfd_elf_link_read_relocs (input_bfd, o, flinfo->external_relocs, + flinfo->internal_relocs, FALSE); if (internal_relocs == NULL && o->reloc_count > 0) return FALSE; @@ -9463,7 +9666,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) if (r_symndx >= locsymcount || (elf_bad_symtab (input_bfd) - && finfo->sections[r_symndx] == NULL)) + && flinfo->sections[r_symndx] == NULL)) { h = sym_hashes[r_symndx - extsymoff]; @@ -9501,13 +9704,13 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) Elf_Internal_Sym *sym = isymbuf + r_symndx; s_type = ELF_ST_TYPE (sym->st_info); - ps = &finfo->sections[r_symndx]; + ps = &flinfo->sections[r_symndx]; sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, *ps); } if ((s_type == STT_RELC || s_type == STT_SRELC) - && !finfo->info->relocatable) + && !flinfo->info->relocatable) { bfd_vma val; bfd_vma dot = (rel->r_offset @@ -9523,7 +9726,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) (unsigned long) rel->r_info, (unsigned long) rel->r_offset); #endif - if (!eval_symbol (&val, &sym_name, input_bfd, finfo, dot, + if (!eval_symbol (&val, &sym_name, input_bfd, flinfo, dot, isymbuf, locsymcount, s_type == STT_SRELC)) return FALSE; @@ -9537,11 +9740,11 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) { /* Complain if the definition comes from a discarded section. */ - if ((sec = *ps) != NULL && elf_discarded_section (sec)) + if ((sec = *ps) != NULL && discarded_section (sec)) { BFD_ASSERT (r_symndx != STN_UNDEF); if (action_discarded & COMPLAIN) - (*finfo->info->callbacks->einfo) + (*flinfo->info->callbacks->einfo) (_("%X`%s' referenced in section `%A' of %B: " "defined in discarded section `%A' of %B\n"), sym_name, o, input_bfd, sec, sec->owner); @@ -9557,7 +9760,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) asection *kept; kept = _bfd_elf_check_kept_section (sec, - finfo->info); + flinfo->info); if (kept != NULL) { *ps = kept; @@ -9588,17 +9791,17 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) corresponding to the output section, which will require the addend to be adjusted. */ - ret = (*relocate_section) (output_bfd, finfo->info, + ret = (*relocate_section) (output_bfd, flinfo->info, input_bfd, o, contents, internal_relocs, isymbuf, - finfo->sections); + flinfo->sections); if (!ret) return FALSE; if (ret == 2 - || finfo->info->relocatable - || finfo->info->emitrelocations) + || flinfo->info->relocatable + || flinfo->info->emitrelocations) { Elf_Internal_Rela *irela; Elf_Internal_Rela *irelaend, *irelamid; @@ -9628,7 +9831,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) rel_hash_list = rel_hash; rela_hash_list = NULL; last_offset = o->output_offset; - if (!finfo->info->relocatable) + if (!flinfo->info->relocatable) last_offset += o->output_section->vma; for (next_erel = 0; irela < irelaend; irela++, next_erel++) { @@ -9650,7 +9853,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) } irela->r_offset = _bfd_elf_section_offset (output_bfd, - finfo->info, o, + flinfo->info, o, irela->r_offset); if (irela->r_offset >= (bfd_vma) -2) { @@ -9668,7 +9871,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) irela->r_offset += o->output_offset; /* Relocs in an executable have to be virtual addresses. */ - if (!finfo->info->relocatable) + if (!flinfo->info->relocatable) irela->r_offset += o->output_section->vma; last_offset = irela->r_offset; @@ -9679,7 +9882,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) if (r_symndx >= locsymcount || (elf_bad_symtab (input_bfd) - && finfo->sections[r_symndx] == NULL)) + && flinfo->sections[r_symndx] == NULL)) { struct elf_link_hash_entry *rh; unsigned long indx; @@ -9712,7 +9915,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) *rel_hash = NULL; sym = isymbuf[r_symndx]; - sec = finfo->sections[r_symndx]; + sec = flinfo->sections[r_symndx]; if (ELF_ST_TYPE (sym.st_info) == STT_SECTION) { /* I suppose the backend ought to fill in the @@ -9749,23 +9952,12 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) r_symndx = osec->target_index; if (r_symndx == STN_UNDEF) { - struct elf_link_hash_table *htab; - asection *oi; - - htab = elf_hash_table (finfo->info); - oi = htab->text_index_section; - if ((osec->flags & SEC_READONLY) == 0 - && htab->data_index_section != NULL) - oi = htab->data_index_section; - - if (oi != NULL) - { - irela->r_addend += osec->vma - oi->vma; - r_symndx = oi->target_index; - } + irela->r_addend += osec->vma; + osec = _bfd_nearby_section (output_bfd, osec, + osec->vma); + irela->r_addend -= osec->vma; + r_symndx = osec->target_index; } - - BFD_ASSERT (r_symndx != STN_UNDEF); } } @@ -9776,14 +9968,14 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) } else { - if (finfo->indices[r_symndx] == -1) + if (flinfo->indices[r_symndx] == -1) { unsigned long shlink; const char *name; asection *osec; long indx; - if (finfo->info->strip == strip_all) + if (flinfo->info->strip == strip_all) { /* You can't do ld -r -s. */ bfd_set_error (bfd_error_invalid_operation); @@ -9807,32 +9999,32 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) return FALSE; sym.st_value += sec->output_offset; - if (! finfo->info->relocatable) + if (!flinfo->info->relocatable) { sym.st_value += osec->vma; if (ELF_ST_TYPE (sym.st_info) == STT_TLS) { /* STT_TLS symbols are relative to PT_TLS segment base. */ - BFD_ASSERT (elf_hash_table (finfo->info) + BFD_ASSERT (elf_hash_table (flinfo->info) ->tls_sec != NULL); - sym.st_value -= (elf_hash_table (finfo->info) + sym.st_value -= (elf_hash_table (flinfo->info) ->tls_sec->vma); } } indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_sym (finfo, name, &sym, sec, + ret = elf_link_output_sym (flinfo, name, &sym, sec, NULL); if (ret == 0) return FALSE; else if (ret == 1) - finfo->indices[r_symndx] = indx; + flinfo->indices[r_symndx] = indx; else abort (); } - r_symndx = finfo->indices[r_symndx]; + r_symndx = flinfo->indices[r_symndx]; } irela->r_info = ((bfd_vma) r_symndx << r_sym_shift @@ -9867,28 +10059,28 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) /* Write out the modified section contents. */ if (bed->elf_backend_write_section - && (*bed->elf_backend_write_section) (output_bfd, finfo->info, o, + && (*bed->elf_backend_write_section) (output_bfd, flinfo->info, o, contents)) { /* Section written out. */ } else switch (o->sec_info_type) { - case ELF_INFO_TYPE_STABS: + case SEC_INFO_TYPE_STABS: if (! (_bfd_write_section_stabs (output_bfd, - &elf_hash_table (finfo->info)->stab_info, + &elf_hash_table (flinfo->info)->stab_info, o, &elf_section_data (o)->sec_info, contents))) return FALSE; break; - case ELF_INFO_TYPE_MERGE: + case SEC_INFO_TYPE_MERGE: if (! _bfd_write_merged_section (output_bfd, o, elf_section_data (o)->sec_info)) return FALSE; break; - case ELF_INFO_TYPE_EH_FRAME: + case SEC_INFO_TYPE_EH_FRAME: { - if (! _bfd_elf_write_section_eh_frame (output_bfd, finfo->info, + if (! _bfd_elf_write_section_eh_frame (output_bfd, flinfo->info, o, contents)) return FALSE; } @@ -10256,6 +10448,42 @@ elf_fixup_link_order (bfd *abfd, asection *o) return TRUE; } +static void +elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo) +{ + asection *o; + + if (flinfo->symstrtab != NULL) + _bfd_stringtab_free (flinfo->symstrtab); + if (flinfo->contents != NULL) + free (flinfo->contents); + if (flinfo->external_relocs != NULL) + free (flinfo->external_relocs); + if (flinfo->internal_relocs != NULL) + free (flinfo->internal_relocs); + if (flinfo->external_syms != NULL) + free (flinfo->external_syms); + if (flinfo->locsym_shndx != NULL) + free (flinfo->locsym_shndx); + if (flinfo->internal_syms != NULL) + free (flinfo->internal_syms); + if (flinfo->indices != NULL) + free (flinfo->indices); + if (flinfo->sections != NULL) + free (flinfo->sections); + if (flinfo->symbuf != NULL) + free (flinfo->symbuf); + if (flinfo->symshndxbuf != NULL) + free (flinfo->symshndxbuf); + for (o = obfd->sections; o != NULL; o = o->next) + { + struct bfd_elf_section_data *esdo = elf_section_data (o); + if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL) + free (esdo->rel.hashes); + if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL) + free (esdo->rela.hashes); + } +} /* Do the final step of an ELF link. */ @@ -10265,7 +10493,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) bfd_boolean dynamic; bfd_boolean emit_relocs; bfd *dynobj; - struct elf_final_link_info finfo; + struct elf_final_link_info flinfo; asection *o; struct bfd_link_order *p; bfd *sub; @@ -10302,39 +10530,40 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) emit_relocs = (info->relocatable || info->emitrelocations); - finfo.info = info; - finfo.output_bfd = abfd; - finfo.symstrtab = _bfd_elf_stringtab_init (); - if (finfo.symstrtab == NULL) + flinfo.info = info; + flinfo.output_bfd = abfd; + flinfo.symstrtab = _bfd_elf_stringtab_init (); + if (flinfo.symstrtab == NULL) return FALSE; if (! dynamic) { - finfo.dynsym_sec = NULL; - finfo.hash_sec = NULL; - finfo.symver_sec = NULL; + flinfo.dynsym_sec = NULL; + flinfo.hash_sec = NULL; + flinfo.symver_sec = NULL; } else { - finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym"); - finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash"); - BFD_ASSERT (finfo.dynsym_sec != NULL); - finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version"); + flinfo.dynsym_sec = bfd_get_linker_section (dynobj, ".dynsym"); + flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash"); + /* Note that dynsym_sec can be NULL (on VMS). */ + flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version"); /* Note that it is OK if symver_sec is NULL. */ } - finfo.contents = NULL; - finfo.external_relocs = NULL; - finfo.internal_relocs = NULL; - finfo.external_syms = NULL; - finfo.locsym_shndx = NULL; - finfo.internal_syms = NULL; - finfo.indices = NULL; - finfo.sections = NULL; - finfo.symbuf = NULL; - finfo.symshndxbuf = NULL; - finfo.symbuf_count = 0; - finfo.shndxbuf_size = 0; + flinfo.contents = NULL; + flinfo.external_relocs = NULL; + flinfo.internal_relocs = NULL; + flinfo.external_syms = NULL; + flinfo.locsym_shndx = NULL; + flinfo.internal_syms = NULL; + flinfo.indices = NULL; + flinfo.sections = NULL; + flinfo.symbuf = NULL; + flinfo.symshndxbuf = NULL; + flinfo.symbuf_count = 0; + flinfo.shndxbuf_size = 0; + flinfo.filesym_count = 0; /* The object attributes have been merged. Remove the input sections from the link, and set the contents of the output @@ -10408,7 +10637,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) if (sec->flags & SEC_MERGE) merged = TRUE; - if (info->relocatable || info->emitrelocations) + if (esdo->this_hdr.sh_type == SHT_REL + || esdo->this_hdr.sh_type == SHT_RELA) + /* Some backends use reloc_count in relocation sections + to count particular types of relocs. Of course, + reloc sections themselves can't have relocations. */ + reloc_count = 0; + else if (info->relocatable || info->emitrelocations) reloc_count = sec->reloc_count; else if (bed->elf_backend_count_relocs) reloc_count = (*bed->elf_backend_count_relocs) (info, sec); @@ -10546,32 +10781,32 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* sh_offset is set just below. */ symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align; - off = elf_tdata (abfd)->next_file_pos; + off = elf_next_file_pos (abfd); off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE); - /* Note that at this point elf_tdata (abfd)->next_file_pos is + /* Note that at this point elf_next_file_pos (abfd) is incorrect. We do not yet know the size of the .symtab section. We correct next_file_pos below, after we do know the size. */ /* Allocate a buffer to hold swapped out symbols. This is to avoid continuously seeking to the right position in the file. */ if (! info->keep_memory || max_sym_count < 20) - finfo.symbuf_size = 20; + flinfo.symbuf_size = 20; else - finfo.symbuf_size = max_sym_count; - amt = finfo.symbuf_size; + flinfo.symbuf_size = max_sym_count; + amt = flinfo.symbuf_size; amt *= bed->s->sizeof_sym; - finfo.symbuf = (bfd_byte *) bfd_malloc (amt); - if (finfo.symbuf == NULL) + flinfo.symbuf = (bfd_byte *) bfd_malloc (amt); + if (flinfo.symbuf == NULL) goto error_return; if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF)) { /* Wild guess at number of output symbols. realloc'd as needed. */ amt = 2 * max_sym_count + elf_numsections (abfd) + 1000; - finfo.shndxbuf_size = amt; + flinfo.shndxbuf_size = amt; amt *= sizeof (Elf_External_Sym_Shndx); - finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt); - if (finfo.symshndxbuf == NULL) + flinfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt); + if (flinfo.symshndxbuf == NULL) goto error_return; } @@ -10586,7 +10821,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) elfsym.st_other = 0; elfsym.st_shndx = SHN_UNDEF; elfsym.st_target_internal = 0; - if (elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr, + if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr, NULL) != 1) goto error_return; } @@ -10613,7 +10848,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) elfsym.st_shndx = i; if (!info->relocatable) elfsym.st_value = o->vma; - if (elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL) != 1) + if (elf_link_output_sym (&flinfo, NULL, &elfsym, o, NULL) != 1) goto error_return; } } @@ -10623,15 +10858,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) files. */ if (max_contents_size != 0) { - finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); - if (finfo.contents == NULL) + flinfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); + if (flinfo.contents == NULL) goto error_return; } if (max_external_reloc_size != 0) { - finfo.external_relocs = bfd_malloc (max_external_reloc_size); - if (finfo.external_relocs == NULL) + flinfo.external_relocs = bfd_malloc (max_external_reloc_size); + if (flinfo.external_relocs == NULL) goto error_return; } @@ -10639,39 +10874,39 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) { amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel; amt *= sizeof (Elf_Internal_Rela); - finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt); - if (finfo.internal_relocs == NULL) + flinfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt); + if (flinfo.internal_relocs == NULL) goto error_return; } if (max_sym_count != 0) { amt = max_sym_count * bed->s->sizeof_sym; - finfo.external_syms = (bfd_byte *) bfd_malloc (amt); - if (finfo.external_syms == NULL) + flinfo.external_syms = (bfd_byte *) bfd_malloc (amt); + if (flinfo.external_syms == NULL) goto error_return; amt = max_sym_count * sizeof (Elf_Internal_Sym); - finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt); - if (finfo.internal_syms == NULL) + flinfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt); + if (flinfo.internal_syms == NULL) goto error_return; amt = max_sym_count * sizeof (long); - finfo.indices = (long int *) bfd_malloc (amt); - if (finfo.indices == NULL) + flinfo.indices = (long int *) bfd_malloc (amt); + if (flinfo.indices == NULL) goto error_return; amt = max_sym_count * sizeof (asection *); - finfo.sections = (asection **) bfd_malloc (amt); - if (finfo.sections == NULL) + flinfo.sections = (asection **) bfd_malloc (amt); + if (flinfo.sections == NULL) goto error_return; } if (max_sym_shndx_count != 0) { amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx); - finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); - if (finfo.locsym_shndx == NULL) + flinfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); + if (flinfo.locsym_shndx == NULL) goto error_return; } @@ -10745,7 +10980,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) { if (! sub->output_has_begun) { - if (! elf_link_input_bfd (&finfo, sub)) + if (! elf_link_input_bfd (&flinfo, sub)) goto error_return; sub->output_has_begun = TRUE; } @@ -10803,6 +11038,17 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) } } + /* Output a FILE symbol so that following locals are not associated + with the wrong input file. */ + memset (&elfsym, 0, sizeof (elfsym)); + elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + elfsym.st_shndx = SHN_ABS; + + if (flinfo.filesym_count > 1 + && !elf_link_output_sym (&flinfo, NULL, &elfsym, + bfd_und_section_ptr, NULL)) + return FALSE; + /* Output any global symbols that got converted to local in a version script or due to symbol visibility. We do this in a separate step since ELF requires all local symbols to appear @@ -10810,12 +11056,27 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) some global symbols were, in fact, converted to become local. FIXME: Will this work correctly with the Irix 5 linker? */ eoinfo.failed = FALSE; - eoinfo.finfo = &finfo; + eoinfo.flinfo = &flinfo; eoinfo.localsyms = TRUE; + eoinfo.need_second_pass = FALSE; + eoinfo.second_pass = FALSE; bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); if (eoinfo.failed) return FALSE; + if (flinfo.filesym_count == 1 + && !elf_link_output_sym (&flinfo, NULL, &elfsym, + bfd_und_section_ptr, NULL)) + return FALSE; + + if (eoinfo.need_second_pass) + { + eoinfo.second_pass = TRUE; + bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); + if (eoinfo.failed) + return FALSE; + } + /* If backend needs to output some local symbols not present in the hash table, do it now. */ if (bed->elf_backend_output_arch_local_syms) @@ -10825,7 +11086,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) struct elf_link_hash_entry *); if (! ((*bed->elf_backend_output_arch_local_syms) - (abfd, info, &finfo, (out_sym_func) elf_link_output_sym))) + (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym))) return FALSE; } @@ -10838,10 +11099,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) symtab_hdr->sh_info = bfd_get_symcount (abfd); if (dynamic - && finfo.dynsym_sec->output_section != bfd_abs_section_ptr) + && flinfo.dynsym_sec != NULL + && flinfo.dynsym_sec->output_section != bfd_abs_section_ptr) { Elf_Internal_Sym sym; - bfd_byte *dynsym = finfo.dynsym_sec->contents; + bfd_byte *dynsym = flinfo.dynsym_sec->contents; long last_local = 0; /* Write out the section symbols for the output sections. */ @@ -10913,14 +11175,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) } } - elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = + elf_section_data (flinfo.dynsym_sec->output_section)->this_hdr.sh_info = last_local + 1; } /* We get the global symbols from the hash table. */ eoinfo.failed = FALSE; eoinfo.localsyms = FALSE; - eoinfo.finfo = &finfo; + eoinfo.flinfo = &flinfo; bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); if (eoinfo.failed) return FALSE; @@ -10934,12 +11196,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) struct elf_link_hash_entry *); if (! ((*bed->elf_backend_output_arch_syms) - (abfd, info, &finfo, (out_sym_func) elf_link_output_sym))) + (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym))) return FALSE; } /* Flush all symbols to the file. */ - if (! elf_link_flush_output_syms (&finfo, bed)) + if (! elf_link_flush_output_syms (&flinfo, bed)) return FALSE; /* Now we know the size of the symtab section. */ @@ -10958,7 +11220,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) off, TRUE); if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0 - || (bfd_bwrite (finfo.symshndxbuf, amt, abfd) != amt)) + || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt)) return FALSE; } @@ -10970,7 +11232,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) symstrtab_hdr->sh_type = SHT_STRTAB; symstrtab_hdr->sh_flags = 0; symstrtab_hdr->sh_addr = 0; - symstrtab_hdr->sh_size = _bfd_stringtab_size (finfo.symstrtab); + symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab); symstrtab_hdr->sh_entsize = 0; symstrtab_hdr->sh_link = 0; symstrtab_hdr->sh_info = 0; @@ -10978,12 +11240,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) symstrtab_hdr->sh_addralign = 1; off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, TRUE); - elf_tdata (abfd)->next_file_pos = off; + elf_next_file_pos (abfd) = off; if (bfd_get_symcount (abfd) > 0) { if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 - || ! _bfd_stringtab_emit (abfd, finfo.symstrtab)) + || ! _bfd_stringtab_emit (abfd, flinfo.symstrtab)) return FALSE; } @@ -11014,7 +11276,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) bfd_byte *dyncon, *dynconend; /* Fix up .dynamic entries. */ - o = bfd_get_section_by_name (dynobj, ".dynamic"); + o = bfd_get_linker_section (dynobj, ".dynamic"); BFD_ASSERT (o != NULL); dyncon = o->contents; @@ -11190,7 +11452,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Check for DT_TEXTREL (late, in case the backend removes it). */ if (((info->warn_shared_textrel && info->shared) || info->error_textrel) - && (o = bfd_get_section_by_name (dynobj, ".dynamic")) != NULL) + && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL) { bfd_byte *dyncon, *dynconend; @@ -11231,9 +11493,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) continue; if (elf_hash_table (info)->eh_info.hdr_sec == o) continue; - if ((elf_section_data (o->output_section)->this_hdr.sh_type - != SHT_STRTAB) - && (strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)) + if (strcmp (o->name, ".dynstr") != 0) { /* FIXME: octets_per_byte. */ if (! bfd_set_section_contents (abfd, o->output_section, @@ -11271,44 +11531,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) goto error_return; } - if (info->eh_frame_hdr) - { - if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info)) - goto error_return; - } + if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info)) + goto error_return; - if (finfo.symstrtab != NULL) - _bfd_stringtab_free (finfo.symstrtab); - if (finfo.contents != NULL) - free (finfo.contents); - if (finfo.external_relocs != NULL) - free (finfo.external_relocs); - if (finfo.internal_relocs != NULL) - free (finfo.internal_relocs); - if (finfo.external_syms != NULL) - free (finfo.external_syms); - if (finfo.locsym_shndx != NULL) - free (finfo.locsym_shndx); - if (finfo.internal_syms != NULL) - free (finfo.internal_syms); - if (finfo.indices != NULL) - free (finfo.indices); - if (finfo.sections != NULL) - free (finfo.sections); - if (finfo.symbuf != NULL) - free (finfo.symbuf); - if (finfo.symshndxbuf != NULL) - free (finfo.symshndxbuf); - for (o = abfd->sections; o != NULL; o = o->next) - { - struct bfd_elf_section_data *esdo = elf_section_data (o); - if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL) - free (esdo->rel.hashes); - if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL) - free (esdo->rela.hashes); - } + elf_final_link_free (abfd, &flinfo); - elf_tdata (abfd)->linker = TRUE; + elf_linker (abfd) = TRUE; if (attr_section) { @@ -11323,37 +11551,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) return TRUE; error_return: - if (finfo.symstrtab != NULL) - _bfd_stringtab_free (finfo.symstrtab); - if (finfo.contents != NULL) - free (finfo.contents); - if (finfo.external_relocs != NULL) - free (finfo.external_relocs); - if (finfo.internal_relocs != NULL) - free (finfo.internal_relocs); - if (finfo.external_syms != NULL) - free (finfo.external_syms); - if (finfo.locsym_shndx != NULL) - free (finfo.locsym_shndx); - if (finfo.internal_syms != NULL) - free (finfo.internal_syms); - if (finfo.indices != NULL) - free (finfo.indices); - if (finfo.sections != NULL) - free (finfo.sections); - if (finfo.symbuf != NULL) - free (finfo.symbuf); - if (finfo.symshndxbuf != NULL) - free (finfo.symshndxbuf); - for (o = abfd->sections; o != NULL; o = o->next) - { - struct bfd_elf_section_data *esdo = elf_section_data (o); - if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL) - free (esdo->rel.hashes); - if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL) - free (esdo->rela.hashes); - } - + elf_final_link_free (abfd, &flinfo); return FALSE; } @@ -11531,7 +11729,7 @@ _bfd_elf_gc_mark_hook (asection *sec, if (sec_name && *sec_name != '\0') { bfd *i; - + for (i = info->input_bfds; i; i = i->link_next) { sec = bfd_get_section_by_name (i, sec_name); @@ -11575,6 +11773,12 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; h->mark = 1; + /* If this symbol is weak and there is a non-weak definition, we + keep the non-weak definition because many backends put + dynamic reloc info on the non-weak definition for code + handling copy relocs. */ + if (h->u.weakdef != NULL) + h->u.weakdef->mark = 1; return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); } @@ -11597,7 +11801,8 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info, rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); if (rsec && !rsec->gc_mark) { - if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour) + if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour + || (rsec->owner->flags & DYNAMIC) != 0) rsec->gc_mark = 1; else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook)) return FALSE; @@ -12008,12 +12213,14 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) struct elf_reloc_cookie cookie; sec = bfd_get_section_by_name (sub, ".eh_frame"); - if (sec && init_reloc_cookie_for_section (&cookie, info, sec)) + while (sec && init_reloc_cookie_for_section (&cookie, info, sec)) { _bfd_elf_parse_eh_frame (sub, info, sec, &cookie); - if (elf_section_data (sec)->sec_info) + if (elf_section_data (sec)->sec_info + && (sec->flags & SEC_LINKER_CREATED) == 0) elf_eh_frame_section (sub) = sec; fini_reloc_cookie_for_section (&cookie, sec); + sec = bfd_get_next_section_by_name (sec); } } _bfd_elf_end_eh_frame_parsing (info); @@ -12229,58 +12436,73 @@ static elf_flags_to_name_table elf_flags_to_names [] = { "SHF_EXCLUDE", SHF_EXCLUDE }, }; -void +/* Returns TRUE if the section is to be included, otherwise FALSE. */ +bfd_boolean bfd_elf_lookup_section_flags (struct bfd_link_info *info, - struct flag_info *finfo) + struct flag_info *flaginfo, + asection *section) { - bfd *output_bfd = info->output_bfd; - const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); - struct flag_info_list *tf = finfo->flag_list; - int with_hex = 0; - int without_hex = 0; + const bfd_vma sh_flags = elf_section_flags (section); - for (tf = finfo->flag_list; tf != NULL; tf = tf->next) + if (!flaginfo->flags_initialized) { - int i; - if (bed->elf_backend_lookup_section_flags_hook) + bfd *obfd = info->output_bfd; + const struct elf_backend_data *bed = get_elf_backend_data (obfd); + struct flag_info_list *tf = flaginfo->flag_list; + int with_hex = 0; + int without_hex = 0; + + for (tf = flaginfo->flag_list; tf != NULL; tf = tf->next) { - flagword hexval = - (*bed->elf_backend_lookup_section_flags_hook) ((char *) tf->name); + unsigned i; + flagword (*lookup) (char *); - if (hexval != 0) + lookup = bed->elf_backend_lookup_section_flags_hook; + if (lookup != NULL) { - if (tf->with == with_flags) - with_hex |= hexval; - else if (tf->with == without_flags) - without_hex |= hexval; - tf->valid = TRUE; - continue; + flagword hexval = (*lookup) ((char *) tf->name); + + if (hexval != 0) + { + if (tf->with == with_flags) + with_hex |= hexval; + else if (tf->with == without_flags) + without_hex |= hexval; + tf->valid = TRUE; + continue; + } } - } - for (i = 0; i < 12; i++) - { - if (!strcmp (tf->name, elf_flags_to_names[i].flag_name)) + for (i = 0; i < ARRAY_SIZE (elf_flags_to_names); ++i) { - if (tf->with == with_flags) - with_hex |= elf_flags_to_names[i].flag_value; - else if (tf->with == without_flags) - without_hex |= elf_flags_to_names[i].flag_value; - tf->valid = TRUE; - continue; + if (strcmp (tf->name, elf_flags_to_names[i].flag_name) == 0) + { + if (tf->with == with_flags) + with_hex |= elf_flags_to_names[i].flag_value; + else if (tf->with == without_flags) + without_hex |= elf_flags_to_names[i].flag_value; + tf->valid = TRUE; + break; + } } - } - if (tf->valid == FALSE) - { - info->callbacks->einfo + if (!tf->valid) + { + info->callbacks->einfo (_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name); - return; + return FALSE; + } } + flaginfo->flags_initialized = TRUE; + flaginfo->only_with_flags |= with_hex; + flaginfo->not_with_flags |= without_hex; } - finfo->flags_initialized = TRUE; - finfo->only_with_flags |= with_hex; - finfo->not_with_flags |= without_hex; - return; + if ((flaginfo->only_with_flags & sh_flags) != flaginfo->only_with_flags) + return FALSE; + + if ((flaginfo->not_with_flags & sh_flags) != 0) + return FALSE; + + return TRUE; } struct alloc_got_off_arg { @@ -12423,7 +12645,7 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) - && elf_discarded_section (h->root.u.def.section)) + && discarded_section (h->root.u.def.section)) return TRUE; else return FALSE; @@ -12439,7 +12661,7 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) /* Need to: get the symbol; get the section. */ isym = &rcookie->locsyms[r_symndx]; isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx); - if (isec != NULL && elf_discarded_section (isec)) + if (isec != NULL && discarded_section (isec)) return TRUE; } return FALSE; @@ -12473,24 +12695,21 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) bed = get_elf_backend_data (abfd); - if ((abfd->flags & DYNAMIC) != 0) - continue; - eh = NULL; if (!info->relocatable) { eh = bfd_get_section_by_name (abfd, ".eh_frame"); - if (eh != NULL - && (eh->size == 0 - || bfd_is_abs_section (eh->output_section))) - eh = NULL; + while (eh != NULL + && (eh->size == 0 + || bfd_is_abs_section (eh->output_section))) + eh = bfd_get_next_section_by_name (eh); } stab = bfd_get_section_by_name (abfd, ".stab"); if (stab != NULL && (stab->size == 0 || bfd_is_abs_section (stab->output_section) - || stab->sec_info_type != ELF_INFO_TYPE_STABS)) + || stab->sec_info_type != SEC_INFO_TYPE_STABS)) stab = NULL; if (stab == NULL @@ -12513,8 +12732,8 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) fini_reloc_cookie_rels (&cookie, stab); } - if (eh != NULL - && init_reloc_cookie_rels (&cookie, info, abfd, eh)) + while (eh != NULL + && init_reloc_cookie_rels (&cookie, info, abfd, eh)) { _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie); if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, @@ -12522,6 +12741,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) &cookie)) ret = TRUE; fini_reloc_cookie_rels (&cookie, eh); + eh = bfd_get_next_section_by_name (eh); } if (bed->elf_backend_discard_info != NULL @@ -12734,7 +12954,7 @@ get_dynamic_reloc_section_name (bfd * abfd, return NULL; name = bfd_alloc (abfd, strlen (prefix) + strlen (old_name) + 1); - sprintf (name, "%s%s", prefix, old_name); + sprintf (name, "%s%s", prefix, old_name); return name; } @@ -12757,7 +12977,7 @@ _bfd_elf_get_dynamic_reloc_section (bfd * abfd, if (name != NULL) { - reloc_sec = bfd_get_section_by_name (abfd, name); + reloc_sec = bfd_get_linker_section (abfd, name); if (reloc_sec != NULL) elf_section_data (sec)->sreloc = reloc_sec; @@ -12793,17 +13013,16 @@ _bfd_elf_make_dynamic_reloc_section (asection * sec, if (name == NULL) return NULL; - reloc_sec = bfd_get_section_by_name (dynobj, name); + reloc_sec = bfd_get_linker_section (dynobj, name); if (reloc_sec == NULL) { - flagword flags; - - flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED); + flagword flags = (SEC_HAS_CONTENTS | SEC_READONLY + | SEC_IN_MEMORY | SEC_LINKER_CREATED); if ((sec->flags & SEC_ALLOC) != 0) flags |= SEC_ALLOC | SEC_LOAD; - reloc_sec = bfd_make_section_with_flags (dynobj, name, flags); + reloc_sec = bfd_make_section_anyway_with_flags (dynobj, name, flags); if (reloc_sec != NULL) { if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment)) @@ -12849,5 +13068,5 @@ elf_append_rel (bfd *abfd, asection *s, Elf_Internal_Rela *rel) const struct elf_backend_data *bed = get_elf_backend_data (abfd); bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rel); BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size); - bed->s->swap_reloca_out (abfd, rel, loc); + bed->s->swap_reloc_out (abfd, rel, loc); } diff --git a/contrib/gdb-7/bfd/elfxx-target.h b/contrib/gdb-7/bfd/elfxx-target.h index 96ecce308d..86c9b1bad4 100644 --- a/contrib/gdb-7/bfd/elfxx-target.h +++ b/contrib/gdb-7/bfd/elfxx-target.h @@ -1,6 +1,6 @@ /* Target definitions for NN-bit ELF Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -109,6 +109,9 @@ #ifndef elf_backend_default_execstack #define elf_backend_default_execstack 1 #endif +#ifndef elf_backend_stack_align +#define elf_backend_stack_align 16 +#endif #define bfd_elfNN_bfd_debug_info_start bfd_void #define bfd_elfNN_bfd_debug_info_end bfd_void @@ -229,14 +232,13 @@ _bfd_elf_canonicalize_dynamic_reloc #endif -#ifndef bfd_elfNN_bfd_link_hash_table_free -#define bfd_elfNN_bfd_link_hash_table_free _bfd_generic_link_hash_table_free -#endif - #ifdef elf_backend_relocate_section #ifndef bfd_elfNN_bfd_link_hash_table_create #define bfd_elfNN_bfd_link_hash_table_create _bfd_elf_link_hash_table_create #endif +#ifndef bfd_elfNN_bfd_link_hash_table_free +#define bfd_elfNN_bfd_link_hash_table_free _bfd_elf_link_hash_table_free +#endif #ifndef bfd_elfNN_bfd_link_add_symbols #define bfd_elfNN_bfd_link_add_symbols bfd_elf_link_add_symbols #endif @@ -253,6 +255,9 @@ #define bfd_elfNN_bfd_link_hash_table_create \ _bfd_generic_link_hash_table_create #endif +#ifndef bfd_elfNN_bfd_link_hash_table_free +#define bfd_elfNN_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +#endif #ifndef bfd_elfNN_bfd_link_add_symbols #define bfd_elfNN_bfd_link_add_symbols _bfd_generic_link_add_symbols #endif @@ -655,6 +660,10 @@ #define elf_backend_is_function_type _bfd_elf_is_function_type #endif +#ifndef elf_backend_maybe_function_sym +#define elf_backend_maybe_function_sym _bfd_elf_maybe_function_sym +#endif + #ifndef elf_match_priority #define elf_match_priority \ (ELF_ARCH == bfd_arch_unknown ? 2 : ELF_OSABI == ELFOSABI_NONE ? 1 : 0) @@ -750,6 +759,7 @@ static struct elf_backend_data elfNN_bed = elf_backend_merge_symbol, elf_backend_hash_symbol, elf_backend_is_function_type, + elf_backend_maybe_function_sym, elf_backend_link_order_error_handler, elf_backend_relplt_name, ELF_MACHINE_ALT1, @@ -765,6 +775,7 @@ static struct elf_backend_data elfNN_bed = elf_backend_obj_attrs_order, elf_backend_obj_attrs_handle_unknown, elf_backend_static_tls_alignment, + elf_backend_stack_align, elf_backend_collect, elf_backend_type_change_ok, elf_backend_may_use_rel_p, diff --git a/contrib/gdb-7/bfd/format.c b/contrib/gdb-7/bfd/format.c index 66b9051efe..e2afa3b2b4 100644 --- a/contrib/gdb-7/bfd/format.c +++ b/contrib/gdb-7/bfd/format.c @@ -95,6 +95,91 @@ bfd_check_format (bfd *abfd, bfd_format format) return bfd_check_format_matches (abfd, format, NULL); } +struct bfd_preserve +{ + void *marker; + void *tdata; + flagword flags; + const struct bfd_arch_info *arch_info; + struct bfd_section *sections; + struct bfd_section *section_last; + unsigned int section_count; + struct bfd_hash_table section_htab; +}; + +/* When testing an object for compatibility with a particular target + back-end, the back-end object_p function needs to set up certain + fields in the bfd on successfully recognizing the object. This + typically happens in a piecemeal fashion, with failures possible at + many points. On failure, the bfd is supposed to be restored to its + initial state, which is virtually impossible. However, restoring a + subset of the bfd state works in practice. This function stores + the subset. */ + +static bfd_boolean +bfd_preserve_save (bfd *abfd, struct bfd_preserve *preserve) +{ + preserve->tdata = abfd->tdata.any; + preserve->arch_info = abfd->arch_info; + preserve->flags = abfd->flags; + preserve->sections = abfd->sections; + preserve->section_last = abfd->section_last; + preserve->section_count = abfd->section_count; + preserve->section_htab = abfd->section_htab; + preserve->marker = bfd_alloc (abfd, 1); + if (preserve->marker == NULL) + return FALSE; + + return bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc, + sizeof (struct section_hash_entry)); +} + +/* Clear out a subset of BFD state. */ + +static void +bfd_reinit (bfd *abfd) +{ + abfd->tdata.any = NULL; + abfd->arch_info = &bfd_default_arch_struct; + abfd->flags &= BFD_FLAGS_SAVED; + bfd_section_list_clear (abfd); +} + +/* Restores bfd state saved by bfd_preserve_save. */ + +static void +bfd_preserve_restore (bfd *abfd, struct bfd_preserve *preserve) +{ + bfd_hash_table_free (&abfd->section_htab); + + abfd->tdata.any = preserve->tdata; + abfd->arch_info = preserve->arch_info; + abfd->flags = preserve->flags; + abfd->section_htab = preserve->section_htab; + abfd->sections = preserve->sections; + abfd->section_last = preserve->section_last; + abfd->section_count = preserve->section_count; + + /* bfd_release frees all memory more recently bfd_alloc'd than + its arg, as well as its arg. */ + bfd_release (abfd, preserve->marker); + preserve->marker = NULL; +} + +/* Called when the bfd state saved by bfd_preserve_save is no longer + needed. */ + +static void +bfd_preserve_finish (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_preserve *preserve) +{ + /* It would be nice to be able to free more memory here, eg. old + tdata, but that's not possible since these blocks are sitting + inside bfd_alloc'd memory. The section hash is on a separate + objalloc. */ + bfd_hash_table_free (&preserve->section_htab); + preserve->marker = NULL; +} + /* FUNCTION bfd_check_format_matches @@ -124,6 +209,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) const bfd_target *save_targ, *right_targ, *ar_right_targ, *match_targ; int match_count, best_count, best_match; int ar_match_index; + struct bfd_preserve preserve; if (matching != NULL) *matching = NULL; @@ -138,12 +224,6 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) if (abfd->format != bfd_unknown) return abfd->format == format; - /* Since the target type was defaulted, check them - all in the hope that one will be uniquely recognized. */ - save_targ = abfd->xvec; - match_count = 0; - ar_match_index = _bfd_target_vector_entries; - if (matching != NULL || *bfd_associated_vector != NULL) { bfd_size_type amt; @@ -154,14 +234,10 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) return FALSE; } - right_targ = 0; - ar_right_targ = 0; - match_targ = 0; - best_match = 256; - best_count = 0; - /* Presume the answer is yes. */ abfd->format = format; + save_targ = abfd->xvec; + preserve.marker = NULL; /* If the target type was explicitly specified, just check that target. */ if (!abfd->target_defaulted) @@ -190,10 +266,19 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) goto err_unrecog; } + /* Since the target type was defaulted, check them all in the hope + that one will be uniquely recognized. */ + right_targ = NULL; + ar_right_targ = NULL; + match_targ = NULL; + best_match = 256; + best_count = 0; + match_count = 0; + ar_match_index = _bfd_target_vector_entries; + for (target = bfd_target_vector; *target != NULL; target++) { const bfd_target *temp; - bfd_error_type err; /* Don't check the default target twice. */ if (*target == &binary_vec @@ -201,7 +286,13 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) || (*target)->match_priority > best_match) continue; - abfd->xvec = *target; /* Change BFD's target temporarily. */ + /* If we already tried a match, the bfd is modified and may + have sections attached, which will confuse the next + _bfd_check_format call. */ + bfd_reinit (abfd); + + /* Change BFD's target temporarily. */ + abfd->xvec = *target; if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) goto err_ret; @@ -214,44 +305,51 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); if (temp) - match_targ = temp; - - if (temp && (abfd->format != bfd_archive || bfd_has_map (abfd))) { - /* This format checks out as ok! */ - right_targ = temp; + match_targ = temp; + if (preserve.marker != NULL) + bfd_preserve_finish (abfd, &preserve); - /* If this is the default target, accept it, even if other - targets might match. People who want those other targets - have to set the GNUTARGET variable. */ - if (temp == bfd_default_vector[0]) - goto ok_ret; - - if (matching_vector) - matching_vector[match_count] = temp; - match_count++; - - if (temp->match_priority < best_match) + if (abfd->format != bfd_archive + || (bfd_has_map (abfd) + && bfd_get_error () != bfd_error_wrong_object_format)) { - best_match = temp->match_priority; - best_count = 0; + /* This format checks out as ok! */ + right_targ = temp; + + /* If this is the default target, accept it, even if + other targets might match. People who want those + other targets have to set the GNUTARGET variable. */ + if (temp == bfd_default_vector[0]) + goto ok_ret; + + if (matching_vector) + matching_vector[match_count] = temp; + match_count++; + + if (temp->match_priority < best_match) + { + best_match = temp->match_priority; + best_count = 0; + } + best_count++; } - best_count++; - } - else if (temp - || (err = bfd_get_error ()) == bfd_error_wrong_object_format - || err == bfd_error_file_ambiguously_recognized) - { - /* An archive with no armap or objects of the wrong type, - or an ambiguous match. We want this target to match - if we get no better matches. */ - if (ar_right_targ != bfd_default_vector[0]) - ar_right_targ = *target; - if (matching_vector) - matching_vector[ar_match_index] = *target; - ar_match_index++; + else + { + /* An archive with no armap or objects of the wrong + type. We want this target to match if we get no + better matches. */ + if (ar_right_targ != bfd_default_vector[0]) + ar_right_targ = *target; + if (matching_vector) + matching_vector[ar_match_index] = *target; + ar_match_index++; + } + + if (!bfd_preserve_save (abfd, &preserve)) + goto err_ret; } - else if (err != bfd_error_wrong_format) + else if (bfd_get_error () != bfd_error_wrong_format) goto err_ret; } @@ -298,6 +396,13 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) } } + /* There is way too much undoing of half-known state here. We + really shouldn't iterate on live bfd's. Note that saving the + whole bfd and restoring it would be even worse; the first thing + you notice is that the cached bfd file position gets out of sync. */ + if (preserve.marker != NULL) + bfd_preserve_restore (abfd, &preserve); + if (match_count == 1) { abfd->xvec = right_targ; @@ -306,9 +411,11 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) state (except possibly for XVEC). */ if (match_targ != right_targ) { + bfd_reinit (abfd); if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) goto err_ret; match_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + BFD_ASSERT (match_targ != NULL); } ok_ret: @@ -322,7 +429,9 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) if (matching_vector) free (matching_vector); - return TRUE; /* File position has moved, BTW. */ + + /* File position has moved, BTW. */ + return TRUE; } if (match_count == 0) @@ -334,11 +443,14 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) abfd->format = bfd_unknown; if (matching_vector) free (matching_vector); + if (preserve.marker != NULL) + bfd_preserve_restore (abfd, &preserve); return FALSE; } - abfd->xvec = save_targ; /* Restore original target type. */ - abfd->format = bfd_unknown; /* Restore original format. */ + /* Restore original target type and format. */ + abfd->xvec = save_targ; + abfd->format = bfd_unknown; bfd_set_error (bfd_error_file_ambiguously_recognized); if (matching) diff --git a/contrib/gdb-7/bfd/hash.c b/contrib/gdb-7/bfd/hash.c index 1de2c2a85b..f2dce4cd18 100644 --- a/contrib/gdb-7/bfd/hash.c +++ b/contrib/gdb-7/bfd/hash.c @@ -1,6 +1,6 @@ /* hash.c -- hash table routines for BFD Copyright 1993, 1994, 1995, 1997, 1999, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc. + 2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Written by Steve Chamberlain This file is part of BFD, the Binary File Descriptor library. @@ -538,7 +538,7 @@ bfd_hash_insert (struct bfd_hash_table *table, table->frozen = 1; return hashp; } - memset ((PTR) newtable, 0, alloc); + memset (newtable, 0, alloc); for (hi = 0; hi < table->size; hi ++) while (table->table[hi]) diff --git a/contrib/gdb-7/bfd/libbfd.c b/contrib/gdb-7/bfd/libbfd.c index 44651cf9c3..553c729562 100644 --- a/contrib/gdb-7/bfd/libbfd.c +++ b/contrib/gdb-7/bfd/libbfd.c @@ -1117,6 +1117,19 @@ _bfd_generic_find_line (bfd *abfd ATTRIBUTE_UNUSED, return FALSE; } +bfd_boolean +_bfd_generic_find_nearest_line_discriminator (bfd *abfd ATTRIBUTE_UNUSED, + asection *section ATTRIBUTE_UNUSED, + asymbol **symbols ATTRIBUTE_UNUSED, + bfd_vma offset ATTRIBUTE_UNUSED, + const char **filename_ptr ATTRIBUTE_UNUSED, + const char **functionname_ptr ATTRIBUTE_UNUSED, + unsigned int *line_ptr ATTRIBUTE_UNUSED, + unsigned int *discriminator_ptr ATTRIBUTE_UNUSED) +{ + return FALSE; +} + bfd_boolean _bfd_generic_init_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED, asection *isec ATTRIBUTE_UNUSED, diff --git a/contrib/gdb-7/bfd/libbfd.h b/contrib/gdb-7/bfd/libbfd.h index d08c2ba829..857d1ea3b7 100644 --- a/contrib/gdb-7/bfd/libbfd.h +++ b/contrib/gdb-7/bfd/libbfd.h @@ -8,7 +8,7 @@ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010, 2011 + 2010, 2011, 2012 Free Software Foundation, Inc. Written by Cygnus Support. @@ -69,16 +69,17 @@ struct section_hash_entry /* tdata for an archive. For an input archive, cache needs to be free()'d. For an output archive, symdefs do. */ -struct artdata { +struct artdata +{ file_ptr first_file_filepos; /* Speed up searching the armap */ htab_t cache; - bfd *archive_head; /* Only interesting in output routines */ - carsym *symdefs; /* the symdef entries */ - symindex symdef_count; /* how many there are */ - char *extended_names; /* clever intel extension */ - bfd_size_type extended_names_size; /* Size of extended names */ - /* when more compilers are standard C, this can be a time_t */ + bfd *archive_head; /* Only interesting in output routines. */ + carsym *symdefs; /* The symdef entries. */ + symindex symdef_count; /* How many there are. */ + char *extended_names; /* Clever intel extension. */ + bfd_size_type extended_names_size; /* Size of extended names. */ + /* When more compilers are standard C, this can be a time_t. */ long armap_timestamp; /* Timestamp value written into armap. This is used for BSD archives to check that the timestamp is recent enough @@ -93,12 +94,15 @@ struct artdata { #define bfd_ardata(bfd) ((bfd)->tdata.aout_ar_data) /* Goes in bfd's arelt_data slot */ -struct areltdata { - char * arch_header; /* it's actually a string */ - unsigned int parsed_size; /* octets of filesize not including ar_hdr */ - unsigned int extra_size; /* BSD4.4: extra bytes after the header. */ - char *filename; /* null-terminated */ - file_ptr origin; /* for element of a thin archive */ +struct areltdata +{ + char * arch_header; /* It's actually a string. */ + bfd_size_type parsed_size; /* Octets of filesize not including ar_hdr. */ + bfd_size_type extra_size; /* BSD4.4: extra bytes after the header. */ + char *filename; /* Null-terminated. */ + file_ptr origin; /* For element of a thin archive. */ + void *parent_cache; /* Where and how to find this member. */ + file_ptr key; }; #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) @@ -120,6 +124,7 @@ extern void *bfd_zmalloc2 extern void _bfd_default_error_handler (const char *s, ...); extern bfd_error_handler_type _bfd_error_handler; +extern bfd_assert_handler_type _bfd_assert_handler; /* These routines allocate and free things on the BFD's objalloc. */ @@ -162,8 +167,6 @@ extern bfd *_bfd_generic_get_elt_at_index (bfd *, symindex); bfd * _bfd_new_bfd (void); -void _bfd_delete_bfd - (bfd *); bfd_boolean _bfd_free_cached_info (bfd *); @@ -208,6 +211,8 @@ extern void *_bfd_generic_read_ar_hdr (bfd *); extern void _bfd_ar_spacepad (char *, size_t, const char *, long); +extern bfd_boolean _bfd_ar_sizepad + (char *, size_t, bfd_size_type); extern void *_bfd_generic_read_ar_hdr_mag (bfd *, const char *); @@ -232,7 +237,9 @@ int bfd_generic_stat_arch_elt /* Generic routines to use for BFD_JUMP_TABLE_GENERIC. Use BFD_JUMP_TABLE_GENERIC (_bfd_generic). */ -#define _bfd_generic_close_and_cleanup bfd_true +#define _bfd_generic_close_and_cleanup _bfd_archive_close_and_cleanup +extern bfd_boolean _bfd_archive_close_and_cleanup + (bfd *); #define _bfd_generic_bfd_free_cached_info bfd_true extern bfd_boolean _bfd_generic_new_section_hook (bfd *, asection *); @@ -459,7 +466,7 @@ extern bfd_boolean _bfd_generic_set_section_contents ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) \ bfd_false) #define _bfd_nolink_bfd_lookup_section_flags \ - ((void (*) (struct bfd_link_info *, struct flag_info *)) \ + ((bfd_boolean (*) (struct bfd_link_info *, struct flag_info *, asection *)) \ bfd_0) #define _bfd_nolink_bfd_merge_sections \ ((bfd_boolean (*) (bfd *, struct bfd_link_info *)) \ @@ -540,20 +547,33 @@ extern const struct dwarf_debug_section dwarf_debug_sections[]; /* Find the nearest line using DWARF 2 debugging information. */ extern bfd_boolean _bfd_dwarf2_find_nearest_line (bfd *, const struct dwarf_debug_section *, asection *, asymbol **, bfd_vma, - const char **, const char **, unsigned int *, unsigned int, void **); + const char **, const char **, unsigned int *, unsigned int *, unsigned int, + void **); /* Find the line using DWARF 2 debugging information. */ extern bfd_boolean _bfd_dwarf2_find_line (bfd *, asymbol **, asymbol *, const char **, - unsigned int *, unsigned int, void **); + unsigned int *, unsigned int *, unsigned int, void **); bfd_boolean _bfd_generic_find_line (bfd *, asymbol **, asymbol *, const char **, unsigned int *); +bfd_boolean _bfd_generic_find_nearest_line_discriminator + (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, + unsigned int *, unsigned int *); + /* Find inliner info after calling bfd_find_nearest_line. */ extern bfd_boolean _bfd_dwarf2_find_inliner_info (bfd *, const char **, const char **, unsigned int *, void **); - + +/* Read DWARF 2 debugging information. */ +extern bfd_boolean _bfd_dwarf2_slurp_debug_info + (bfd *, bfd *, const struct dwarf_debug_section *, asymbol **, void **); + +/* Clean up the data used to handle DWARF 2 debugging information. */ +extern void _bfd_dwarf2_cleanup_debug_info + (bfd *, void **); + /* Create a new section entry. */ extern struct bfd_hash_entry *bfd_section_hash_newfunc (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); @@ -692,6 +712,10 @@ extern bfd_boolean _bfd_write_merged_section extern bfd_vma _bfd_merged_section_offset (bfd *, asection **, void *, bfd_vma); +/* Tidy up when done. */ + +extern void _bfd_merge_sections_free (void *); + /* Create a string table. */ extern struct bfd_strtab_hash *_bfd_stringtab_init (void); @@ -920,6 +944,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_HI16_PLTOFF", "BFD_RELOC_HI16_S_PLTOFF", "BFD_RELOC_8_PLTOFF", + "BFD_RELOC_SIZE32", + "BFD_RELOC_SIZE64", "BFD_RELOC_68K_GLOB_DAT", "BFD_RELOC_68K_JMP_SLOT", "BFD_RELOC_68K_RELATIVE", @@ -1002,6 +1028,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_SPARC_M44", "BFD_RELOC_SPARC_L44", "BFD_RELOC_SPARC_REGISTER", + "BFD_RELOC_SPARC_H34", + "BFD_RELOC_SPARC_SIZE32", + "BFD_RELOC_SPARC_SIZE64", + "BFD_RELOC_SPARC_WDISP10", "BFD_RELOC_SPARC_REV32", "BFD_RELOC_SPARC_TLS_GD_HI22", "BFD_RELOC_SPARC_TLS_GD_LO10", @@ -1086,6 +1116,13 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MIPS16_HI16", "BFD_RELOC_MIPS16_HI16_S", "BFD_RELOC_MIPS16_LO16", + "BFD_RELOC_MIPS16_TLS_GD", + "BFD_RELOC_MIPS16_TLS_LDM", + "BFD_RELOC_MIPS16_TLS_DTPREL_HI16", + "BFD_RELOC_MIPS16_TLS_DTPREL_LO16", + "BFD_RELOC_MIPS16_TLS_GOTTPREL", + "BFD_RELOC_MIPS16_TLS_TPREL_HI16", + "BFD_RELOC_MIPS16_TLS_TPREL_LO16", "BFD_RELOC_MIPS_LITERAL", "BFD_RELOC_MICROMIPS_LITERAL", "BFD_RELOC_MICROMIPS_7_PCREL_S1", @@ -1206,6 +1243,17 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MN10300_RELATIVE", "BFD_RELOC_MN10300_SYM_DIFF", "BFD_RELOC_MN10300_ALIGN", + "BFD_RELOC_MN10300_TLS_GD", + "BFD_RELOC_MN10300_TLS_LD", + "BFD_RELOC_MN10300_TLS_LDO", + "BFD_RELOC_MN10300_TLS_GOTIE", + "BFD_RELOC_MN10300_TLS_IE", + "BFD_RELOC_MN10300_TLS_LE", + "BFD_RELOC_MN10300_TLS_DTPMOD", + "BFD_RELOC_MN10300_TLS_DTPOFF", + "BFD_RELOC_MN10300_TLS_TPOFF", + "BFD_RELOC_MN10300_32_PCREL", + "BFD_RELOC_MN10300_16_PCREL", "BFD_RELOC_386_GOT32", "BFD_RELOC_386_PLT32", @@ -1308,6 +1356,23 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_PPC_EMB_RELST_HA", "BFD_RELOC_PPC_EMB_BIT_FLD", "BFD_RELOC_PPC_EMB_RELSDA", + "BFD_RELOC_PPC_VLE_REL8", + "BFD_RELOC_PPC_VLE_REL15", + "BFD_RELOC_PPC_VLE_REL24", + "BFD_RELOC_PPC_VLE_LO16A", + "BFD_RELOC_PPC_VLE_LO16D", + "BFD_RELOC_PPC_VLE_HI16A", + "BFD_RELOC_PPC_VLE_HI16D", + "BFD_RELOC_PPC_VLE_HA16A", + "BFD_RELOC_PPC_VLE_HA16D", + "BFD_RELOC_PPC_VLE_SDA21", + "BFD_RELOC_PPC_VLE_SDA21_LO", + "BFD_RELOC_PPC_VLE_SDAREL_LO16A", + "BFD_RELOC_PPC_VLE_SDAREL_LO16D", + "BFD_RELOC_PPC_VLE_SDAREL_HI16A", + "BFD_RELOC_PPC_VLE_SDAREL_HI16D", + "BFD_RELOC_PPC_VLE_SDAREL_HA16A", + "BFD_RELOC_PPC_VLE_SDAREL_HA16D", "BFD_RELOC_PPC64_HIGHER", "BFD_RELOC_PPC64_HIGHER_S", "BFD_RELOC_PPC64_HIGHEST", @@ -1714,8 +1779,6 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_V850_32_GOTOFF", "BFD_RELOC_V850_CODE", "BFD_RELOC_V850_DATA", - "BFD_RELOC_MN10300_32_PCREL", - "BFD_RELOC_MN10300_16_PCREL", "BFD_RELOC_TIC30_LDP", "BFD_RELOC_TIC54X_PARTLS7", "BFD_RELOC_TIC54X_PARTMS9", @@ -1787,6 +1850,44 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MEP_GNU_VTINHERIT", "BFD_RELOC_MEP_GNU_VTENTRY", + "BFD_RELOC_METAG_HIADDR16", + "BFD_RELOC_METAG_LOADDR16", + "BFD_RELOC_METAG_RELBRANCH", + "BFD_RELOC_METAG_GETSETOFF", + "BFD_RELOC_METAG_HIOG", + "BFD_RELOC_METAG_LOOG", + "BFD_RELOC_METAG_REL8", + "BFD_RELOC_METAG_REL16", + "BFD_RELOC_METAG_HI16_GOTOFF", + "BFD_RELOC_METAG_LO16_GOTOFF", + "BFD_RELOC_METAG_GETSET_GOTOFF", + "BFD_RELOC_METAG_GETSET_GOT", + "BFD_RELOC_METAG_HI16_GOTPC", + "BFD_RELOC_METAG_LO16_GOTPC", + "BFD_RELOC_METAG_HI16_PLT", + "BFD_RELOC_METAG_LO16_PLT", + "BFD_RELOC_METAG_RELBRANCH_PLT", + "BFD_RELOC_METAG_GOTOFF", + "BFD_RELOC_METAG_PLT", + "BFD_RELOC_METAG_COPY", + "BFD_RELOC_METAG_JMP_SLOT", + "BFD_RELOC_METAG_RELATIVE", + "BFD_RELOC_METAG_GLOB_DAT", + "BFD_RELOC_METAG_TLS_GD", + "BFD_RELOC_METAG_TLS_LDM", + "BFD_RELOC_METAG_TLS_LDO_HI16", + "BFD_RELOC_METAG_TLS_LDO_LO16", + "BFD_RELOC_METAG_TLS_LDO", + "BFD_RELOC_METAG_TLS_IE", + "BFD_RELOC_METAG_TLS_IENONPIC", + "BFD_RELOC_METAG_TLS_IENONPIC_HI16", + "BFD_RELOC_METAG_TLS_IENONPIC_LO16", + "BFD_RELOC_METAG_TLS_TPOFF", + "BFD_RELOC_METAG_TLS_DTPMOD", + "BFD_RELOC_METAG_TLS_DTPOFF", + "BFD_RELOC_METAG_TLS_LE", + "BFD_RELOC_METAG_TLS_LE_HI16", + "BFD_RELOC_METAG_TLS_LE_LO16", "BFD_RELOC_MMIX_GETA", "BFD_RELOC_MMIX_GETA_1", "BFD_RELOC_MMIX_GETA_2", @@ -1834,6 +1935,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_AVR_LDI", "BFD_RELOC_AVR_6", "BFD_RELOC_AVR_6_ADIW", + "BFD_RELOC_AVR_8_LO", + "BFD_RELOC_AVR_8_HI", + "BFD_RELOC_AVR_8_HLO", "BFD_RELOC_RL78_NEG8", "BFD_RELOC_RL78_NEG16", "BFD_RELOC_RL78_NEG24", @@ -1866,6 +1970,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_RL78_HI16", "BFD_RELOC_RL78_HI8", "BFD_RELOC_RL78_LO16", + "BFD_RELOC_RL78_CODE", "BFD_RELOC_RX_NEG8", "BFD_RELOC_RX_NEG16", "BFD_RELOC_RX_NEG24", @@ -1943,6 +2048,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_390_GOT20", "BFD_RELOC_390_GOTPLT20", "BFD_RELOC_390_TLS_GOTIE20", + "BFD_RELOC_390_IRELATIVE", "BFD_RELOC_SCORE_GPREL15", "BFD_RELOC_SCORE_DUMMY2", "BFD_RELOC_SCORE_JMP", @@ -2060,6 +2166,24 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_M68HC11_PAGE", "BFD_RELOC_M68HC11_24", "BFD_RELOC_M68HC12_5B", + "BFD_RELOC_XGATE_RL_JUMP", + "BFD_RELOC_XGATE_RL_GROUP", + "BFD_RELOC_XGATE_LO16", + "BFD_RELOC_XGATE_GPAGE", + "BFD_RELOC_XGATE_24", + "BFD_RELOC_XGATE_PCREL_9", + "BFD_RELOC_XGATE_PCREL_10", + "BFD_RELOC_XGATE_IMM8_LO", + "BFD_RELOC_XGATE_IMM8_HI", + "BFD_RELOC_XGATE_IMM3", + "BFD_RELOC_XGATE_IMM4", + "BFD_RELOC_XGATE_IMM5", + "BFD_RELOC_M68HC12_9B", + "BFD_RELOC_M68HC12_16B", + "BFD_RELOC_M68HC12_9_PCREL", + "BFD_RELOC_M68HC12_10_PCREL", + "BFD_RELOC_M68HC12_LO8XG", + "BFD_RELOC_M68HC12_HI8XG", "BFD_RELOC_16C_NUM08", "BFD_RELOC_16C_NUM08_C", "BFD_RELOC_16C_NUM16", @@ -2251,6 +2375,40 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MSP430_16_BYTE", "BFD_RELOC_MSP430_2X_PCREL", "BFD_RELOC_MSP430_RL_PCREL", + "BFD_RELOC_NIOS2_S16", + "BFD_RELOC_NIOS2_U16", + "BFD_RELOC_NIOS2_CALL26", + "BFD_RELOC_NIOS2_IMM5", + "BFD_RELOC_NIOS2_CACHE_OPX", + "BFD_RELOC_NIOS2_IMM6", + "BFD_RELOC_NIOS2_IMM8", + "BFD_RELOC_NIOS2_HI16", + "BFD_RELOC_NIOS2_LO16", + "BFD_RELOC_NIOS2_HIADJ16", + "BFD_RELOC_NIOS2_GPREL", + "BFD_RELOC_NIOS2_UJMP", + "BFD_RELOC_NIOS2_CJMP", + "BFD_RELOC_NIOS2_CALLR", + "BFD_RELOC_NIOS2_ALIGN", + "BFD_RELOC_NIOS2_GOT16", + "BFD_RELOC_NIOS2_CALL16", + "BFD_RELOC_NIOS2_GOTOFF_LO", + "BFD_RELOC_NIOS2_GOTOFF_HA", + "BFD_RELOC_NIOS2_PCREL_LO", + "BFD_RELOC_NIOS2_PCREL_HA", + "BFD_RELOC_NIOS2_TLS_GD16", + "BFD_RELOC_NIOS2_TLS_LDM16", + "BFD_RELOC_NIOS2_TLS_LDO16", + "BFD_RELOC_NIOS2_TLS_IE16", + "BFD_RELOC_NIOS2_TLS_LE16", + "BFD_RELOC_NIOS2_TLS_DTPMOD", + "BFD_RELOC_NIOS2_TLS_DTPREL", + "BFD_RELOC_NIOS2_TLS_TPREL", + "BFD_RELOC_NIOS2_COPY", + "BFD_RELOC_NIOS2_GLOB_DAT", + "BFD_RELOC_NIOS2_JUMP_SLOT", + "BFD_RELOC_NIOS2_RELATIVE", + "BFD_RELOC_NIOS2_GOTOFF", "BFD_RELOC_IQ2000_OFFSET_16", "BFD_RELOC_IQ2000_OFFSET_21", "BFD_RELOC_IQ2000_UHI16", @@ -2318,6 +2476,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_LM32_JMP_SLOT", "BFD_RELOC_LM32_RELATIVE", "BFD_RELOC_MACH_O_SECTDIFF", + "BFD_RELOC_MACH_O_LOCAL_SECTDIFF", "BFD_RELOC_MACH_O_PAIR", "BFD_RELOC_MACH_O_X86_64_BRANCH32", "BFD_RELOC_MACH_O_X86_64_BRANCH8", @@ -2340,6 +2499,72 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MICROBLAZE_64_GOTOFF", "BFD_RELOC_MICROBLAZE_32_GOTOFF", "BFD_RELOC_MICROBLAZE_COPY", + "BFD_RELOC_MICROBLAZE_64_TLS", + "BFD_RELOC_MICROBLAZE_64_TLSGD", + "BFD_RELOC_MICROBLAZE_64_TLSLD", + "BFD_RELOC_MICROBLAZE_32_TLSDTPMOD", + "BFD_RELOC_MICROBLAZE_32_TLSDTPREL", + "BFD_RELOC_MICROBLAZE_64_TLSDTPREL", + "BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL", + "BFD_RELOC_MICROBLAZE_64_TLSTPREL", + "BFD_RELOC_AARCH64_ADD_LO12", + "BFD_RELOC_AARCH64_GOT_LD_PREL19", + "BFD_RELOC_AARCH64_ADR_GOT_PAGE", + "BFD_RELOC_AARCH64_ADR_HI21_PCREL", + "BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL", + "BFD_RELOC_AARCH64_ADR_LO21_PCREL", + "BFD_RELOC_AARCH64_BRANCH19", + "BFD_RELOC_AARCH64_CALL26", + "BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP", + "BFD_RELOC_AARCH64_JUMP26", + "BFD_RELOC_AARCH64_LD_LO19_PCREL", + "BFD_RELOC_AARCH64_LD64_GOT_LO12_NC", + "BFD_RELOC_AARCH64_LDST_LO12", + "BFD_RELOC_AARCH64_LDST8_LO12", + "BFD_RELOC_AARCH64_LDST16_LO12", + "BFD_RELOC_AARCH64_LDST32_LO12", + "BFD_RELOC_AARCH64_LDST64_LO12", + "BFD_RELOC_AARCH64_LDST128_LO12", + "BFD_RELOC_AARCH64_MOVW_G0", + "BFD_RELOC_AARCH64_MOVW_G0_S", + "BFD_RELOC_AARCH64_MOVW_G0_NC", + "BFD_RELOC_AARCH64_MOVW_G1", + "BFD_RELOC_AARCH64_MOVW_G1_NC", + "BFD_RELOC_AARCH64_MOVW_G1_S", + "BFD_RELOC_AARCH64_MOVW_G2", + "BFD_RELOC_AARCH64_MOVW_G2_NC", + "BFD_RELOC_AARCH64_MOVW_G2_S", + "BFD_RELOC_AARCH64_MOVW_G3", + "BFD_RELOC_AARCH64_TLSDESC", + "BFD_RELOC_AARCH64_TLSDESC_ADD", + "BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC", + "BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE", + "BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21", + "BFD_RELOC_AARCH64_TLSDESC_CALL", + "BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC", + "BFD_RELOC_AARCH64_TLSDESC_LD64_PREL19", + "BFD_RELOC_AARCH64_TLSDESC_LDR", + "BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC", + "BFD_RELOC_AARCH64_TLSDESC_OFF_G1", + "BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC", + "BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21", + "BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21", + "BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19", + "BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", + "BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC", + "BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1", + "BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12", + "BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12", + "BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC", + "BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0", + "BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC", + "BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1", + "BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC", + "BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2", + "BFD_RELOC_AARCH64_TLS_DTPMOD64", + "BFD_RELOC_AARCH64_TLS_DTPREL64", + "BFD_RELOC_AARCH64_TLS_TPREL64", + "BFD_RELOC_AARCH64_TSTBR14", "BFD_RELOC_TILEPRO_COPY", "BFD_RELOC_TILEPRO_GLOB_DAT", "BFD_RELOC_TILEPRO_JMP_SLOT", @@ -2386,6 +2611,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_TILEPRO_SHAMT_X1", "BFD_RELOC_TILEPRO_SHAMT_Y0", "BFD_RELOC_TILEPRO_SHAMT_Y1", + "BFD_RELOC_TILEPRO_TLS_GD_CALL", + "BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD", + "BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD", + "BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD", + "BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD", + "BFD_RELOC_TILEPRO_TLS_IE_LOAD", "BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD", "BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD", "BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO", @@ -2405,6 +2636,14 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_TILEPRO_TLS_DTPMOD32", "BFD_RELOC_TILEPRO_TLS_DTPOFF32", "BFD_RELOC_TILEPRO_TLS_TPOFF32", + "BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE", + "BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE", + "BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO", + "BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO", + "BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI", + "BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI", + "BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA", + "BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA", "BFD_RELOC_TILEGX_HW0", "BFD_RELOC_TILEGX_HW1", "BFD_RELOC_TILEGX_HW2", @@ -2462,52 +2701,58 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PCREL", "BFD_RELOC_TILEGX_IMM16_X0_HW0_GOT", "BFD_RELOC_TILEGX_IMM16_X1_HW0_GOT", - "BFD_RELOC_TILEGX_IMM16_X0_HW1_GOT", - "BFD_RELOC_TILEGX_IMM16_X1_HW1_GOT", - "BFD_RELOC_TILEGX_IMM16_X0_HW2_GOT", - "BFD_RELOC_TILEGX_IMM16_X1_HW2_GOT", - "BFD_RELOC_TILEGX_IMM16_X0_HW3_GOT", - "BFD_RELOC_TILEGX_IMM16_X1_HW3_GOT", + "BFD_RELOC_TILEGX_IMM16_X0_HW0_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X1_HW0_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X0_HW1_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X1_HW1_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X0_HW2_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X1_HW2_PLT_PCREL", "BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_GOT", "BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_GOT", "BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_GOT", "BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_GOT", - "BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_GOT", - "BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_GOT", + "BFD_RELOC_TILEGX_IMM16_X0_HW3_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X1_HW3_PLT_PCREL", "BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD", "BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD", - "BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_GD", - "BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_GD", - "BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_GD", - "BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_GD", - "BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_GD", - "BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_GD", + "BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE", + "BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE", + "BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE", + "BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE", + "BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE", + "BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE", "BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD", "BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD", "BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD", "BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD", - "BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_GD", - "BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_GD", "BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE", "BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE", - "BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_IE", - "BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_IE", - "BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_IE", - "BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_IE", - "BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_IE", - "BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_IE", + "BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL", + "BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL", "BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE", "BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE", "BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE", "BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE", - "BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_IE", - "BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_IE", "BFD_RELOC_TILEGX_TLS_DTPMOD64", "BFD_RELOC_TILEGX_TLS_DTPOFF64", "BFD_RELOC_TILEGX_TLS_TPOFF64", "BFD_RELOC_TILEGX_TLS_DTPMOD32", "BFD_RELOC_TILEGX_TLS_DTPOFF32", "BFD_RELOC_TILEGX_TLS_TPOFF32", + "BFD_RELOC_TILEGX_TLS_GD_CALL", + "BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD", + "BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD", + "BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD", + "BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD", + "BFD_RELOC_TILEGX_TLS_IE_LOAD", + "BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD", + "BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD", + "BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD", + "BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD", "BFD_RELOC_EPIPHANY_SIMM8", "BFD_RELOC_EPIPHANY_SIMM24", "BFD_RELOC_EPIPHANY_HIGH", @@ -2531,8 +2776,8 @@ bfd_boolean bfd_generic_relax_section bfd_boolean bfd_generic_gc_sections (bfd *, struct bfd_link_info *); -void bfd_generic_lookup_section_flags - (struct bfd_link_info *, struct flag_info *); +bfd_boolean bfd_generic_lookup_section_flags + (struct bfd_link_info *, struct flag_info *, asection *); bfd_boolean bfd_generic_merge_sections (bfd *, struct bfd_link_info *); @@ -2556,4 +2801,8 @@ const bfd_arch_info_type *bfd_default_compatible bfd_boolean bfd_default_scan (const struct bfd_arch_info *info, const char *string); +void *bfd_arch_default_fill (bfd_size_type count, + bfd_boolean is_bigendian, + bfd_boolean code); + /* Extracted from elf.c. */ diff --git a/contrib/gdb-7/bfd/libcoff.h b/contrib/gdb-7/bfd/libcoff.h index 8aef552701..6270bab86b 100644 --- a/contrib/gdb-7/bfd/libcoff.h +++ b/contrib/gdb-7/bfd/libcoff.h @@ -354,6 +354,9 @@ extern asymbol *coff_bfd_make_debug_symbol extern bfd_boolean coff_find_nearest_line (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, unsigned int *); +extern bfd_boolean coff_find_nearest_line_discriminator + (bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *, unsigned int *); struct dwarf_debug_section; extern bfd_boolean coff_find_nearest_line_with_names (bfd *, const struct dwarf_debug_section *, asection *, asymbol **, @@ -730,7 +733,7 @@ typedef struct bfd_boolean _bfd_coff_long_section_names; bfd_boolean (*_bfd_coff_set_long_section_names) (bfd *, int); - + unsigned int _bfd_coff_default_section_alignment_power; bfd_boolean _bfd_coff_force_symnames_in_strings; unsigned int _bfd_coff_debug_string_prefix_length; diff --git a/contrib/gdb-7/bfd/linker.c b/contrib/gdb-7/bfd/linker.c index 7a01e114a2..190520a57f 100644 --- a/contrib/gdb-7/bfd/linker.c +++ b/contrib/gdb-7/bfd/linker.c @@ -1,6 +1,6 @@ /* linker.c -- BFD linker routines Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support @@ -810,6 +810,7 @@ void _bfd_generic_link_just_syms (asection *sec, struct bfd_link_info *info ATTRIBUTE_UNUSED) { + sec->sec_info_type = SEC_INFO_TYPE_JUST_SYMS; sec->output_section = bfd_abs_section_ptr; sec->output_offset = sec->vma; } @@ -2358,6 +2359,12 @@ _bfd_generic_link_output_symbols (bfd *output_bfd, else output = FALSE; } + else if (sym->flags == 0 + && (sym->section->owner->flags & BFD_PLUGIN) != 0) + /* LTO doesn't set symbol information. We get here with the + generic linker for a symbol that was "common" but no longer + needs to be global. */ + output = FALSE; else abort (); @@ -2664,7 +2671,14 @@ default_data_link_order (bfd *abfd, fill = link_order->u.data.contents; fill_size = link_order->u.data.size; - if (fill_size != 0 && fill_size < size) + if (fill_size == 0) + { + fill = abfd->arch_info->fill (size, bfd_big_endian (abfd), + (sec->flags & SEC_CODE) != 0); + if (fill == NULL) + return FALSE; + } + else if (fill_size < size) { bfd_byte *p; fill = (bfd_byte *) bfd_malloc (size); @@ -2905,7 +2919,7 @@ DESCRIPTION /* Sections marked with the SEC_LINK_ONCE flag should only be linked once into the output. This routine checks each section, and arrange to discard it if a section of the same name has already - been linked. This code assumes that all relevant sections have the + been linked. This code assumes that all relevant sections have the SEC_LINK_ONCE flag set; that is, it does not depend solely upon the section name. bfd_section_already_linked is called via bfd_map_over_sections. */ @@ -3123,6 +3137,76 @@ _bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED, return FALSE; } +/* Choose a neighbouring section to S in OBFD that will be output, or + the absolute section if ADDR is out of bounds of the neighbours. */ + +asection * +_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr) +{ + asection *next, *prev, *best; + + /* Find preceding kept section. */ + for (prev = s->prev; prev != NULL; prev = prev->prev) + if ((prev->flags & SEC_EXCLUDE) == 0 + && !bfd_section_removed_from_list (obfd, prev)) + break; + + /* Find following kept section. Start at prev->next because + other sections may have been added after S was removed. */ + if (s->prev != NULL) + next = s->prev->next; + else + next = s->owner->sections; + for (; next != NULL; next = next->next) + if ((next->flags & SEC_EXCLUDE) == 0 + && !bfd_section_removed_from_list (obfd, next)) + break; + + /* Choose better of two sections, based on flags. The idea + is to choose a section that will be in the same segment + as S would have been if it was kept. */ + best = next; + if (prev == NULL) + { + if (next == NULL) + best = bfd_abs_section_ptr; + } + else if (next == NULL) + best = prev; + else if (((prev->flags ^ next->flags) + & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0) + { + if (((next->flags ^ s->flags) + & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0 + /* We prefer to choose a loaded section. Section S + doesn't have SEC_LOAD set (it being excluded, that + part of the flag processing didn't happen) so we + can't compare that flag to those of NEXT and PREV. */ + || ((prev->flags & SEC_LOAD) != 0 + && (next->flags & SEC_LOAD) == 0)) + best = prev; + } + else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0) + { + if (((next->flags ^ s->flags) & SEC_READONLY) != 0) + best = prev; + } + else if (((prev->flags ^ next->flags) & SEC_CODE) != 0) + { + if (((next->flags ^ s->flags) & SEC_CODE) != 0) + best = prev; + } + else + { + /* Flags we care about are the same. Prefer the following + section if that will result in a positive valued sym. */ + if (addr < next->vma) + best = prev; + } + + return best; +} + /* Convert symbols in excluded output sections to use a kept section. */ static bfd_boolean @@ -3139,68 +3223,10 @@ fix_syms (struct bfd_link_hash_entry *h, void *data) && (s->output_section->flags & SEC_EXCLUDE) != 0 && bfd_section_removed_from_list (obfd, s->output_section)) { - asection *op, *op1; + asection *op; h->u.def.value += s->output_offset + s->output_section->vma; - - /* Find preceding kept section. */ - for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev) - if ((op1->flags & SEC_EXCLUDE) == 0 - && !bfd_section_removed_from_list (obfd, op1)) - break; - - /* Find following kept section. Start at prev->next because - other sections may have been added after S was removed. */ - if (s->output_section->prev != NULL) - op = s->output_section->prev->next; - else - op = s->output_section->owner->sections; - for (; op != NULL; op = op->next) - if ((op->flags & SEC_EXCLUDE) == 0 - && !bfd_section_removed_from_list (obfd, op)) - break; - - /* Choose better of two sections, based on flags. The idea - is to choose a section that will be in the same segment - as S would have been if it was kept. */ - if (op1 == NULL) - { - if (op == NULL) - op = bfd_abs_section_ptr; - } - else if (op == NULL) - op = op1; - else if (((op1->flags ^ op->flags) - & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0) - { - if (((op->flags ^ s->flags) - & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0 - /* We prefer to choose a loaded section. Section S - doesn't have SEC_LOAD set (it being excluded, that - part of the flag processing didn't happen) so we - can't compare that flag to those of OP and OP1. */ - || ((op1->flags & SEC_LOAD) != 0 - && (op->flags & SEC_LOAD) == 0)) - op = op1; - } - else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0) - { - if (((op->flags ^ s->flags) & SEC_READONLY) != 0) - op = op1; - } - else if (((op1->flags ^ op->flags) & SEC_CODE) != 0) - { - if (((op->flags ^ s->flags) & SEC_CODE) != 0) - op = op1; - } - else - { - /* Flags we care about are the same. Prefer the following - section if that will result in a positive valued sym. */ - if (h->u.def.value < op->vma) - op = op1; - } - + op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value); h->u.def.value -= op->vma; h->u.def.section = op; } @@ -3276,7 +3302,7 @@ bfd_generic_define_common_symbol (bfd *output_bfd, /* FUNCTION - bfd_find_version_for_sym + bfd_find_version_for_sym SYNOPSIS struct bfd_elf_version_tree * bfd_find_version_for_sym diff --git a/contrib/gdb-7/bfd/merge.c b/contrib/gdb-7/bfd/merge.c index aef3cf35a5..0e49faeaff 100644 --- a/contrib/gdb-7/bfd/merge.c +++ b/contrib/gdb-7/bfd/merge.c @@ -885,3 +885,17 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, *psec = entry->secinfo->sec; return entry->u.index + (secinfo->contents + offset - p); } + +/* Tidy up when done. */ + +void +_bfd_merge_sections_free (void *xsinfo) +{ + struct sec_merge_info *sinfo; + + for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next) + { + bfd_hash_table_free (&sinfo->htab->table); + free (sinfo->htab); + } +} diff --git a/contrib/gdb-7/bfd/opncls.c b/contrib/gdb-7/bfd/opncls.c index 9d33f3974f..6d61191a96 100644 --- a/contrib/gdb-7/bfd/opncls.c +++ b/contrib/gdb-7/bfd/opncls.c @@ -1,6 +1,6 @@ /* opncls.c -- open and close a BFD. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc. Written by Cygnus Support. @@ -86,7 +86,7 @@ _bfd_new_bfd (void) nbfd->iostream = NULL; nbfd->where = 0; if (!bfd_hash_table_init_n (& nbfd->section_htab, bfd_section_hash_newfunc, - sizeof (struct section_hash_entry), 251)) + sizeof (struct section_hash_entry), 13)) { free (nbfd); return NULL; @@ -107,6 +107,8 @@ _bfd_new_bfd (void) return nbfd; } +static const struct bfd_iovec opncls_iovec; + /* Allocate a new BFD as a member of archive OBFD. */ bfd * @@ -119,6 +121,8 @@ _bfd_new_bfd_contained_in (bfd *obfd) return NULL; nbfd->xvec = obfd->xvec; nbfd->iovec = obfd->iovec; + if (obfd->iovec == &opncls_iovec) + nbfd->iostream = obfd->iostream; nbfd->my_archive = obfd; nbfd->direction = read_direction; nbfd->target_defaulted = obfd->target_defaulted; @@ -127,7 +131,7 @@ _bfd_new_bfd_contained_in (bfd *obfd) /* Delete a BFD. */ -void +static void _bfd_delete_bfd (bfd *abfd) { if (abfd->memory) @@ -135,6 +139,8 @@ _bfd_delete_bfd (bfd *abfd) bfd_hash_table_free (&abfd->section_htab); objalloc_free ((struct objalloc *) abfd->memory); } + + free (abfd->arelt_data); free (abfd); } @@ -180,7 +186,7 @@ DESCRIPTION Return a pointer to the created BFD. If @var{fd} is not -1, then <> is used to open the file; otherwise, <> is used. @var{mode} is passed directly to <> or - <>. + <>. Calls <>, so @var{target} is interpreted as by that function. @@ -190,6 +196,8 @@ DESCRIPTION If <> is returned then an error has occured. Possible errors are <>, <> or <> error. + + On error, @var{fd} is always closed. */ bfd * @@ -200,15 +208,21 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd) nbfd = _bfd_new_bfd (); if (nbfd == NULL) - return NULL; + { + if (fd != -1) + close (fd); + return NULL; + } target_vec = bfd_find_target (target, nbfd); if (target_vec == NULL) { + if (fd != -1) + close (fd); _bfd_delete_bfd (nbfd); return NULL; } - + #ifdef HAVE_FDOPEN if (fd != -1) nbfd->iostream = fdopen (fd, mode); @@ -227,7 +241,7 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd) /* Figure out whether the user is opening the file for reading, writing, or both, by looking at the MODE argument. */ - if ((mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a') + if ((mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a') && mode[1] == '+') nbfd->direction = both_direction; else if (mode[0] == 'r') @@ -307,6 +321,8 @@ DESCRIPTION Possible errors are <>, <> and <>. + + On error, @var{fd} is closed. */ bfd * @@ -323,6 +339,10 @@ bfd_fdopenr (const char *filename, const char *target, int fd) fdflags = fcntl (fd, F_GETFL, NULL); if (fdflags == -1) { + int save = errno; + + close (fd); + errno = save; bfd_set_error (bfd_error_system_call); return NULL; } @@ -693,8 +713,6 @@ bfd_boolean bfd_close (bfd *abfd) { bfd_boolean ret; - bfd *nbfd; - bfd *next; if (bfd_write_p (abfd)) { @@ -702,17 +720,10 @@ bfd_close (bfd *abfd) return FALSE; } - /* Close nested archives (if this bfd is a thin archive). */ - for (nbfd = abfd->nested_archives; nbfd; nbfd = next) - { - next = nbfd->archive_next; - bfd_close (nbfd); - } - if (! BFD_SEND (abfd, _close_and_cleanup, (abfd))) return FALSE; - ret = abfd->iovec->bclose (abfd); + ret = abfd->iovec->bclose (abfd) == 0; if (ret) _maybe_make_executable (abfd); @@ -1124,7 +1135,7 @@ bfd_calc_gnu_debuglink_crc32 (unsigned long crc, crc = ~crc & 0xffffffff; for (end = buf + len; buf < end; ++ buf) crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); - return ~crc & 0xffffffff;; + return ~crc & 0xffffffff; } diff --git a/contrib/gdb-7/bfd/reloc.c b/contrib/gdb-7/bfd/reloc.c index e0b5f620ea..b59ca00e97 100644 --- a/contrib/gdb-7/bfd/reloc.c +++ b/contrib/gdb-7/bfd/reloc.c @@ -1,6 +1,7 @@ /* BFD support for handling relocation entries. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Written by Cygnus Support. @@ -502,7 +503,7 @@ bfd_check_overflow (enum complain_overflow how, fieldmask = N_ONES (bitsize); signmask = ~fieldmask; addrmask = N_ONES (addrsize) | (fieldmask << rightshift); - a = (relocation & addrmask) >> rightshift;; + a = (relocation & addrmask) >> rightshift; switch (how) { @@ -1735,6 +1736,13 @@ ENUMX ENUMDOC For ELF. +ENUM + BFD_RELOC_SIZE32 +ENUMX + BFD_RELOC_SIZE64 +ENUMDOC + Size relocations. + ENUM BFD_RELOC_68K_GLOB_DAT ENUMX @@ -1942,6 +1950,14 @@ ENUMX BFD_RELOC_SPARC_L44 ENUMX BFD_RELOC_SPARC_REGISTER +ENUMX + BFD_RELOC_SPARC_H34 +ENUMX + BFD_RELOC_SPARC_SIZE32 +ENUMX + BFD_RELOC_SPARC_SIZE64 +ENUMX + BFD_RELOC_SPARC_WDISP10 ENUMDOC SPARC64 relocations @@ -2246,6 +2262,23 @@ ENUM ENUMDOC MIPS16 low 16 bits. +ENUM + BFD_RELOC_MIPS16_TLS_GD +ENUMX + BFD_RELOC_MIPS16_TLS_LDM +ENUMX + BFD_RELOC_MIPS16_TLS_DTPREL_HI16 +ENUMX + BFD_RELOC_MIPS16_TLS_DTPREL_LO16 +ENUMX + BFD_RELOC_MIPS16_TLS_GOTTPREL +ENUMX + BFD_RELOC_MIPS16_TLS_TPREL_HI16 +ENUMX + BFD_RELOC_MIPS16_TLS_TPREL_LO16 +ENUMDOC + MIPS16 TLS relocations + ENUM BFD_RELOC_MIPS_LITERAL ENUMX @@ -2530,6 +2563,36 @@ ENUMDOC The addend of this reloc is an alignment power that must be honoured at the offset's location, regardless of linker relaxation. +ENUM + BFD_RELOC_MN10300_TLS_GD +ENUMX + BFD_RELOC_MN10300_TLS_LD +ENUMX + BFD_RELOC_MN10300_TLS_LDO +ENUMX + BFD_RELOC_MN10300_TLS_GOTIE +ENUMX + BFD_RELOC_MN10300_TLS_IE +ENUMX + BFD_RELOC_MN10300_TLS_LE +ENUMX + BFD_RELOC_MN10300_TLS_DTPMOD +ENUMX + BFD_RELOC_MN10300_TLS_DTPOFF +ENUMX + BFD_RELOC_MN10300_TLS_TPOFF +ENUMDOC + Various TLS-related relocations. +ENUM + BFD_RELOC_MN10300_32_PCREL +ENUMDOC + This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the + instruction. +ENUM + BFD_RELOC_MN10300_16_PCREL +ENUMDOC + This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the + instruction. COMMENT ENUM @@ -2749,6 +2812,40 @@ ENUMX BFD_RELOC_PPC_EMB_BIT_FLD ENUMX BFD_RELOC_PPC_EMB_RELSDA +ENUMX + BFD_RELOC_PPC_VLE_REL8 +ENUMX + BFD_RELOC_PPC_VLE_REL15 +ENUMX + BFD_RELOC_PPC_VLE_REL24 +ENUMX + BFD_RELOC_PPC_VLE_LO16A +ENUMX + BFD_RELOC_PPC_VLE_LO16D +ENUMX + BFD_RELOC_PPC_VLE_HI16A +ENUMX + BFD_RELOC_PPC_VLE_HI16D +ENUMX + BFD_RELOC_PPC_VLE_HA16A +ENUMX + BFD_RELOC_PPC_VLE_HA16D +ENUMX + BFD_RELOC_PPC_VLE_SDA21 +ENUMX + BFD_RELOC_PPC_VLE_SDA21_LO +ENUMX + BFD_RELOC_PPC_VLE_SDAREL_LO16A +ENUMX + BFD_RELOC_PPC_VLE_SDAREL_LO16D +ENUMX + BFD_RELOC_PPC_VLE_SDAREL_HI16A +ENUMX + BFD_RELOC_PPC_VLE_SDAREL_HI16D +ENUMX + BFD_RELOC_PPC_VLE_SDAREL_HA16A +ENUMX + BFD_RELOC_PPC_VLE_SDAREL_HA16D ENUMX BFD_RELOC_PPC64_HIGHER ENUMX @@ -3820,100 +3917,90 @@ ENUM BFD_RELOC_V850_16_PCREL ENUMDOC This is a 16-bit reloc. -ENUM +ENUM BFD_RELOC_V850_17_PCREL ENUMDOC This is a 17-bit reloc. -ENUM +ENUM BFD_RELOC_V850_23 ENUMDOC This is a 23-bit reloc. -ENUM +ENUM BFD_RELOC_V850_32_PCREL ENUMDOC This is a 32-bit reloc. -ENUM +ENUM BFD_RELOC_V850_32_ABS ENUMDOC This is a 32-bit reloc. -ENUM +ENUM BFD_RELOC_V850_16_SPLIT_OFFSET ENUMDOC This is a 16-bit reloc. -ENUM +ENUM BFD_RELOC_V850_16_S1 ENUMDOC This is a 16-bit reloc. -ENUM +ENUM BFD_RELOC_V850_LO16_S1 ENUMDOC Low 16 bits. 16 bit shifted by 1. -ENUM +ENUM BFD_RELOC_V850_CALLT_15_16_OFFSET ENUMDOC This is a 16 bit offset from the call table base pointer. -ENUM +ENUM BFD_RELOC_V850_32_GOTPCREL ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_16_GOT ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_32_GOT ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_22_PLT_PCREL ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_32_PLT_PCREL ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_COPY ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_GLOB_DAT ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_JMP_SLOT ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_RELATIVE ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_16_GOTOFF ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_32_GOTOFF ENUMDOC DSO relocations. -ENUM +ENUM BFD_RELOC_V850_CODE ENUMDOC start code. -ENUM +ENUM BFD_RELOC_V850_DATA ENUMDOC start data in text. -ENUM - BFD_RELOC_MN10300_32_PCREL -ENUMDOC - This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the - instruction. -ENUM - BFD_RELOC_MN10300_16_PCREL -ENUMDOC - This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the - instruction. ENUM BFD_RELOC_TIC30_LDP @@ -4117,6 +4204,85 @@ ENUMDOC Toshiba Media Processor Relocations. COMMENT +ENUM + BFD_RELOC_METAG_HIADDR16 +ENUMX + BFD_RELOC_METAG_LOADDR16 +ENUMX + BFD_RELOC_METAG_RELBRANCH +ENUMX + BFD_RELOC_METAG_GETSETOFF +ENUMX + BFD_RELOC_METAG_HIOG +ENUMX + BFD_RELOC_METAG_LOOG +ENUMX + BFD_RELOC_METAG_REL8 +ENUMX + BFD_RELOC_METAG_REL16 +ENUMX + BFD_RELOC_METAG_HI16_GOTOFF +ENUMX + BFD_RELOC_METAG_LO16_GOTOFF +ENUMX + BFD_RELOC_METAG_GETSET_GOTOFF +ENUMX + BFD_RELOC_METAG_GETSET_GOT +ENUMX + BFD_RELOC_METAG_HI16_GOTPC +ENUMX + BFD_RELOC_METAG_LO16_GOTPC +ENUMX + BFD_RELOC_METAG_HI16_PLT +ENUMX + BFD_RELOC_METAG_LO16_PLT +ENUMX + BFD_RELOC_METAG_RELBRANCH_PLT +ENUMX + BFD_RELOC_METAG_GOTOFF +ENUMX + BFD_RELOC_METAG_PLT +ENUMX + BFD_RELOC_METAG_COPY +ENUMX + BFD_RELOC_METAG_JMP_SLOT +ENUMX + BFD_RELOC_METAG_RELATIVE +ENUMX + BFD_RELOC_METAG_GLOB_DAT +ENUMX + BFD_RELOC_METAG_TLS_GD +ENUMX + BFD_RELOC_METAG_TLS_LDM +ENUMX + BFD_RELOC_METAG_TLS_LDO_HI16 +ENUMX + BFD_RELOC_METAG_TLS_LDO_LO16 +ENUMX + BFD_RELOC_METAG_TLS_LDO +ENUMX + BFD_RELOC_METAG_TLS_IE +ENUMX + BFD_RELOC_METAG_TLS_IENONPIC +ENUMX + BFD_RELOC_METAG_TLS_IENONPIC_HI16 +ENUMX + BFD_RELOC_METAG_TLS_IENONPIC_LO16 +ENUMX + BFD_RELOC_METAG_TLS_TPOFF +ENUMX + BFD_RELOC_METAG_TLS_DTPMOD +ENUMX + BFD_RELOC_METAG_TLS_DTPOFF +ENUMX + BFD_RELOC_METAG_TLS_LE +ENUMX + BFD_RELOC_METAG_TLS_LE_HI16 +ENUMX + BFD_RELOC_METAG_TLS_LE_LO16 +ENUMDOC + Imagination Technologies Meta relocations. + ENUM BFD_RELOC_MMIX_GETA ENUMX @@ -4256,7 +4422,7 @@ ENUMDOC ENUM BFD_RELOC_AVR_LO8_LDI_GS ENUMDOC - This is a 16 bit reloc for the AVR that stores 8 bit value + This is a 16 bit reloc for the AVR that stores 8 bit value (command address) into 8 bit immediate value of LDI insn. If the address is beyond the 128k boundary, the linker inserts a jump stub for this reloc in the lower 128k. @@ -4314,6 +4480,21 @@ ENUM ENUMDOC This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw instructions +ENUM + BFD_RELOC_AVR_8_LO +ENUMDOC + This is a 8 bit reloc for the AVR that stores bits 0..7 of a symbol + in .byte lo8(symbol) +ENUM + BFD_RELOC_AVR_8_HI +ENUMDOC + This is a 8 bit reloc for the AVR that stores bits 8..15 of a symbol + in .byte hi8(symbol) +ENUM + BFD_RELOC_AVR_8_HLO +ENUMDOC + This is a 8 bit reloc for the AVR that stores bits 16..23 of a symbol + in .byte hlo8(symbol) ENUM BFD_RELOC_RL78_NEG8 @@ -4379,6 +4560,8 @@ ENUMX BFD_RELOC_RL78_HI8 ENUMX BFD_RELOC_RL78_LO16 +ENUMX + BFD_RELOC_RL78_CODE ENUMDOC Renesas RL78 Relocations. @@ -4598,11 +4781,16 @@ ENUMX ENUMDOC Long displacement extension. +ENUM + BFD_RELOC_390_IRELATIVE +ENUMDOC + STT_GNU_IFUNC relocation. + ENUM BFD_RELOC_SCORE_GPREL15 ENUMDOC Score relocations - Low 16 bit for load/store + Low 16 bit for load/store ENUM BFD_RELOC_SCORE_DUMMY2 ENUMX @@ -4643,7 +4831,7 @@ ENUMX BFD_RELOC_SCORE_DUMMY_HI16 ENUMDOC Undocumented Score relocs - + ENUM BFD_RELOC_IP2K_FR9 ENUMDOC @@ -4933,7 +5121,101 @@ ENUM ENUMDOC Motorola 68HC12 reloc. This is the 5 bits of a value. - +ENUM + BFD_RELOC_XGATE_RL_JUMP +ENUMDOC + Freescale XGATE reloc. + This reloc marks the beginning of a bra/jal instruction. +ENUM + BFD_RELOC_XGATE_RL_GROUP +ENUMDOC + Freescale XGATE reloc. + This reloc marks a group of several instructions that gcc generates + and for which the linker relaxation pass can modify and/or remove + some of them. +ENUM + BFD_RELOC_XGATE_LO16 +ENUMDOC + Freescale XGATE reloc. + This is the 16-bit lower part of an address. It is used for the '16-bit' + instructions. +ENUM + BFD_RELOC_XGATE_GPAGE +ENUMDOC + Freescale XGATE reloc. +ENUM + BFD_RELOC_XGATE_24 +ENUMDOC + Freescale XGATE reloc. +ENUM + BFD_RELOC_XGATE_PCREL_9 +ENUMDOC + Freescale XGATE reloc. + This is a 9-bit pc-relative reloc. +ENUM + BFD_RELOC_XGATE_PCREL_10 +ENUMDOC + Freescale XGATE reloc. + This is a 10-bit pc-relative reloc. +ENUM + BFD_RELOC_XGATE_IMM8_LO +ENUMDOC + Freescale XGATE reloc. + This is the 16-bit lower part of an address. It is used for the '16-bit' + instructions. +ENUM + BFD_RELOC_XGATE_IMM8_HI +ENUMDOC + Freescale XGATE reloc. + This is the 16-bit higher part of an address. It is used for the '16-bit' + instructions. +ENUM + BFD_RELOC_XGATE_IMM3 +ENUMDOC + Freescale XGATE reloc. + This is a 3-bit pc-relative reloc. +ENUM + BFD_RELOC_XGATE_IMM4 +ENUMDOC + Freescale XGATE reloc. + This is a 4-bit pc-relative reloc. +ENUM + BFD_RELOC_XGATE_IMM5 +ENUMDOC + Freescale XGATE reloc. + This is a 5-bit pc-relative reloc. +ENUM + BFD_RELOC_M68HC12_9B +ENUMDOC + Motorola 68HC12 reloc. + This is the 9 bits of a value. +ENUM + BFD_RELOC_M68HC12_16B +ENUMDOC + Motorola 68HC12 reloc. + This is the 16 bits of a value. +ENUM + BFD_RELOC_M68HC12_9_PCREL +ENUMDOC + Motorola 68HC12/XGATE reloc. + This is a PCREL9 branch. +ENUM + BFD_RELOC_M68HC12_10_PCREL +ENUMDOC + Motorola 68HC12/XGATE reloc. + This is a PCREL10 branch. +ENUM + BFD_RELOC_M68HC12_LO8XG +ENUMDOC + Motorola 68HC12/XGATE reloc. + This is the 8 bit low part of an absolute address and immediately precedes + a matching HI8XG part. +ENUM + BFD_RELOC_M68HC12_HI8XG +ENUMDOC + Motorola 68HC12/XGATE reloc. + This is the 8 bit high part of an absolute address and immediately follows + a matching LO8XG part. ENUM BFD_RELOC_16C_NUM08 ENUMX @@ -5384,6 +5666,77 @@ ENUMX ENUMDOC msp430 specific relocation codes +ENUM + BFD_RELOC_NIOS2_S16 +ENUMX + BFD_RELOC_NIOS2_U16 +ENUMX + BFD_RELOC_NIOS2_CALL26 +ENUMX + BFD_RELOC_NIOS2_IMM5 +ENUMX + BFD_RELOC_NIOS2_CACHE_OPX +ENUMX + BFD_RELOC_NIOS2_IMM6 +ENUMX + BFD_RELOC_NIOS2_IMM8 +ENUMX + BFD_RELOC_NIOS2_HI16 +ENUMX + BFD_RELOC_NIOS2_LO16 +ENUMX + BFD_RELOC_NIOS2_HIADJ16 +ENUMX + BFD_RELOC_NIOS2_GPREL +ENUMX + BFD_RELOC_NIOS2_UJMP +ENUMX + BFD_RELOC_NIOS2_CJMP +ENUMX + BFD_RELOC_NIOS2_CALLR +ENUMX + BFD_RELOC_NIOS2_ALIGN +ENUMX + BFD_RELOC_NIOS2_GOT16 +ENUMX + BFD_RELOC_NIOS2_CALL16 +ENUMX + BFD_RELOC_NIOS2_GOTOFF_LO +ENUMX + BFD_RELOC_NIOS2_GOTOFF_HA +ENUMX + BFD_RELOC_NIOS2_PCREL_LO +ENUMX + BFD_RELOC_NIOS2_PCREL_HA +ENUMX + BFD_RELOC_NIOS2_TLS_GD16 +ENUMX + BFD_RELOC_NIOS2_TLS_LDM16 +ENUMX + BFD_RELOC_NIOS2_TLS_LDO16 +ENUMX + BFD_RELOC_NIOS2_TLS_IE16 +ENUMX + BFD_RELOC_NIOS2_TLS_LE16 +ENUMX + BFD_RELOC_NIOS2_TLS_DTPMOD +ENUMX + BFD_RELOC_NIOS2_TLS_DTPREL +ENUMX + BFD_RELOC_NIOS2_TLS_TPREL +ENUMX + BFD_RELOC_NIOS2_COPY +ENUMX + BFD_RELOC_NIOS2_GLOB_DAT +ENUMX + BFD_RELOC_NIOS2_JUMP_SLOT +ENUMX + BFD_RELOC_NIOS2_RELATIVE +ENUMX + BFD_RELOC_NIOS2_GOTOFF +ENUMDOC + Relocations used by the Altera Nios II core. + ENUM BFD_RELOC_IQ2000_OFFSET_16 ENUMX @@ -5576,6 +5929,10 @@ ENUM ENUMDOC Difference between two section addreses. Must be followed by a BFD_RELOC_MACH_O_PAIR. +ENUM + BFD_RELOC_MACH_O_LOCAL_SECTDIFF +ENUMDOC + Like BFD_RELOC_MACH_O_SECTDIFF but with a local symbol. ENUM BFD_RELOC_MACH_O_PAIR ENUMDOC @@ -5621,69 +5978,388 @@ ENUMDOC ENUM BFD_RELOC_MICROBLAZE_32_LO ENUMDOC - This is a 32 bit reloc for the microblaze that stores the + This is a 32 bit reloc for the microblaze that stores the low 16 bits of a value ENUM BFD_RELOC_MICROBLAZE_32_LO_PCREL ENUMDOC - This is a 32 bit pc-relative reloc for the microblaze that + This is a 32 bit pc-relative reloc for the microblaze that stores the low 16 bits of a value ENUM BFD_RELOC_MICROBLAZE_32_ROSDA ENUMDOC - This is a 32 bit reloc for the microblaze that stores a + This is a 32 bit reloc for the microblaze that stores a value relative to the read-only small data area anchor ENUM BFD_RELOC_MICROBLAZE_32_RWSDA ENUMDOC - This is a 32 bit reloc for the microblaze that stores a + This is a 32 bit reloc for the microblaze that stores a value relative to the read-write small data area anchor ENUM BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM ENUMDOC - This is a 32 bit reloc for the microblaze to handle + This is a 32 bit reloc for the microblaze to handle expressions of the form "Symbol Op Symbol" ENUM BFD_RELOC_MICROBLAZE_64_NONE ENUMDOC - This is a 64 bit reloc that stores the 32 bit pc relative - value in two words (with an imm instruction). No relocation is + This is a 64 bit reloc that stores the 32 bit pc relative + value in two words (with an imm instruction). No relocation is done here - only used for relaxing ENUM BFD_RELOC_MICROBLAZE_64_GOTPC ENUMDOC - This is a 64 bit reloc that stores the 32 bit pc relative + This is a 64 bit reloc that stores the 32 bit pc relative value in two words (with an imm instruction). The relocation is PC-relative GOT offset ENUM BFD_RELOC_MICROBLAZE_64_GOT ENUMDOC - This is a 64 bit reloc that stores the 32 bit pc relative + This is a 64 bit reloc that stores the 32 bit pc relative value in two words (with an imm instruction). The relocation is GOT offset ENUM BFD_RELOC_MICROBLAZE_64_PLT ENUMDOC - This is a 64 bit reloc that stores the 32 bit pc relative + This is a 64 bit reloc that stores the 32 bit pc relative value in two words (with an imm instruction). The relocation is PC-relative offset into PLT ENUM BFD_RELOC_MICROBLAZE_64_GOTOFF ENUMDOC - This is a 64 bit reloc that stores the 32 bit GOT relative + This is a 64 bit reloc that stores the 32 bit GOT relative value in two words (with an imm instruction). The relocation is relative offset from _GLOBAL_OFFSET_TABLE_ ENUM BFD_RELOC_MICROBLAZE_32_GOTOFF ENUMDOC - This is a 32 bit reloc that stores the 32 bit GOT relative - value in a word. The relocation is relative offset from + This is a 32 bit reloc that stores the 32 bit GOT relative + value in a word. The relocation is relative offset from _GLOBAL_OFFSET_TABLE_ ENUM BFD_RELOC_MICROBLAZE_COPY ENUMDOC This is used to tell the dynamic linker to copy the value out of the dynamic object into the runtime process image. +ENUM + BFD_RELOC_MICROBLAZE_64_TLS +ENUMDOC + Unused Reloc +ENUM + BFD_RELOC_MICROBLAZE_64_TLSGD +ENUMDOC + This is a 64 bit reloc that stores the 32 bit GOT relative value + of the GOT TLS GD info entry in two words (with an imm instruction). The + relocation is GOT offset. +ENUM + BFD_RELOC_MICROBLAZE_64_TLSLD +ENUMDOC + This is a 64 bit reloc that stores the 32 bit GOT relative value + of the GOT TLS LD info entry in two words (with an imm instruction). The + relocation is GOT offset. +ENUM + BFD_RELOC_MICROBLAZE_32_TLSDTPMOD +ENUMDOC + This is a 32 bit reloc that stores the Module ID to GOT(n). +ENUM + BFD_RELOC_MICROBLAZE_32_TLSDTPREL +ENUMDOC + This is a 32 bit reloc that stores TLS offset to GOT(n+1). +ENUM + BFD_RELOC_MICROBLAZE_64_TLSDTPREL +ENUMDOC + This is a 32 bit reloc for storing TLS offset to two words (uses imm + instruction) +ENUM + BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL +ENUMDOC + This is a 64 bit reloc that stores 32-bit thread pointer relative offset + to two words (uses imm instruction). +ENUM + BFD_RELOC_MICROBLAZE_64_TLSTPREL +ENUMDOC + This is a 64 bit reloc that stores 32-bit thread pointer relative offset + to two words (uses imm instruction). + +ENUM + BFD_RELOC_AARCH64_ADD_LO12 +ENUMDOC + AArch64 ADD immediate instruction, holding bits 0 to 11 of the address. + Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. +ENUM + BFD_RELOC_AARCH64_GOT_LD_PREL19 +ENUMDOC + AArch64 Load Literal instruction, holding a 19 bit PC relative word + offset of the global offset table entry for a symbol. The lowest two + bits must be zero and are not stored in the instruction, giving a 21 + bit signed byte offset. This relocation type requires signed overflow + checking. +ENUM + BFD_RELOC_AARCH64_ADR_GOT_PAGE +ENUMDOC + Get to the page base of the global offset table entry for a symbol as + part of an ADRP instruction using a 21 bit PC relative value.Used in + conjunction with BFD_RELOC_AARCH64_LD64_GOT_LO12_NC. +ENUM + BFD_RELOC_AARCH64_ADR_HI21_PCREL +ENUMDOC + AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page + offset, giving a 4KB aligned page base address. +ENUM + BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL +ENUMDOC + AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page + offset, giving a 4KB aligned page base address, but with no overflow + checking. +ENUM + BFD_RELOC_AARCH64_ADR_LO21_PCREL +ENUMDOC + AArch64 ADR instruction, holding a simple 21 bit pc-relative byte offset. +ENUM + BFD_RELOC_AARCH64_BRANCH19 +ENUMDOC + AArch64 19 bit pc-relative conditional branch and compare & branch. + The lowest two bits must be zero and are not stored in the instruction, + giving a 21 bit signed byte offset. +ENUM + BFD_RELOC_AARCH64_CALL26 +ENUMDOC + AArch64 26 bit pc-relative unconditional branch and link. + The lowest two bits must be zero and are not stored in the instruction, + giving a 28 bit signed byte offset. +ENUM + BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP +ENUMDOC + AArch64 pseudo relocation code to be used internally by the AArch64 + assembler and not (currently) written to any object files. +ENUM + BFD_RELOC_AARCH64_JUMP26 +ENUMDOC + AArch64 26 bit pc-relative unconditional branch. + The lowest two bits must be zero and are not stored in the instruction, + giving a 28 bit signed byte offset. +ENUM + BFD_RELOC_AARCH64_LD_LO19_PCREL +ENUMDOC + AArch64 Load Literal instruction, holding a 19 bit pc-relative word + offset. The lowest two bits must be zero and are not stored in the + instruction, giving a 21 bit signed byte offset. +ENUM + BFD_RELOC_AARCH64_LD64_GOT_LO12_NC +ENUMDOC + Unsigned 12 bit byte offset for 64 bit load/store from the page of + the GOT entry for this symbol. Used in conjunction with + BFD_RELOC_AARCH64_ADR_GOTPAGE. +ENUM + BFD_RELOC_AARCH64_LDST_LO12 +ENUMDOC + AArch64 unspecified load/store instruction, holding bits 0 to 11 of the + address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. +ENUM + BFD_RELOC_AARCH64_LDST8_LO12 +ENUMDOC + AArch64 8-bit load/store instruction, holding bits 0 to 11 of the + address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. +ENUM + BFD_RELOC_AARCH64_LDST16_LO12 +ENUMDOC + AArch64 16-bit load/store instruction, holding bits 0 to 11 of the + address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. +ENUM + BFD_RELOC_AARCH64_LDST32_LO12 +ENUMDOC + AArch64 32-bit load/store instruction, holding bits 0 to 11 of the + address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. +ENUM + BFD_RELOC_AARCH64_LDST64_LO12 +ENUMDOC + AArch64 64-bit load/store instruction, holding bits 0 to 11 of the + address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. +ENUM + BFD_RELOC_AARCH64_LDST128_LO12 +ENUMDOC + AArch64 128-bit load/store instruction, holding bits 0 to 11 of the + address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. +ENUM + BFD_RELOC_AARCH64_MOVW_G0 +ENUMDOC + AArch64 MOV[NZK] instruction with most significant bits 0 to 15 + of an unsigned address/value. +ENUM + BFD_RELOC_AARCH64_MOVW_G0_S +ENUMDOC + AArch64 MOV[NZ] instruction with most significant bits 0 to 15 + of a signed value. Changes instruction to MOVZ or MOVN depending on the + value's sign. +ENUM + BFD_RELOC_AARCH64_MOVW_G0_NC +ENUMDOC + AArch64 MOV[NZK] instruction with less significant bits 0 to 15 of + an address/value. No overflow checking. +ENUM + BFD_RELOC_AARCH64_MOVW_G1 +ENUMDOC + AArch64 MOV[NZK] instruction with most significant bits 16 to 31 + of an unsigned address/value. +ENUM + BFD_RELOC_AARCH64_MOVW_G1_NC +ENUMDOC + AArch64 MOV[NZK] instruction with less significant bits 16 to 31 + of an address/value. No overflow checking. +ENUM + BFD_RELOC_AARCH64_MOVW_G1_S +ENUMDOC + AArch64 MOV[NZ] instruction with most significant bits 16 to 31 + of a signed value. Changes instruction to MOVZ or MOVN depending on the + value's sign. +ENUM + BFD_RELOC_AARCH64_MOVW_G2 +ENUMDOC + AArch64 MOV[NZK] instruction with most significant bits 32 to 47 + of an unsigned address/value. +ENUM + BFD_RELOC_AARCH64_MOVW_G2_NC +ENUMDOC + AArch64 MOV[NZK] instruction with less significant bits 32 to 47 + of an address/value. No overflow checking. +ENUM + BFD_RELOC_AARCH64_MOVW_G2_S +ENUMDOC + AArch64 MOV[NZ] instruction with most significant bits 32 to 47 + of a signed value. Changes instruction to MOVZ or MOVN depending on the + value's sign. +ENUM + BFD_RELOC_AARCH64_MOVW_G3 +ENUMDOC + AArch64 MOV[NZK] instruction with most signficant bits 48 to 64 + of a signed or unsigned address/value. +ENUM + BFD_RELOC_AARCH64_TLSDESC +ENUMDOC + AArch64 TLS relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_ADD +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_CALL +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_LD64_PREL19 +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_LDR +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSDESC_OFF_G1 +ENUMDOC + AArch64 TLS DESC relocation. +ENUM + BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC +ENUMDOC + Unsigned 12 bit byte offset to global offset table entry for a symbols + tls_index structure. Used in conjunction with + BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21. +ENUM + BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 +ENUMDOC + Get to the page base of the global offset table entry for a symbols + tls_index structure as part of an adrp instruction using a 21 bit PC + relative value. Used in conjunction with + BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC. +ENUM + BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 +ENUMDOC + AArch64 TLS INITIAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 +ENUMDOC + AArch64 TLS INITIAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC +ENUMDOC + AArch64 TLS INITIAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC +ENUMDOC + AArch64 TLS INITIAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1 +ENUMDOC + AArch64 TLS INITIAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12 +ENUMDOC + AArch64 TLS LOCAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12 +ENUMDOC + AArch64 TLS LOCAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC +ENUMDOC + AArch64 TLS LOCAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0 +ENUMDOC + AArch64 TLS LOCAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC +ENUMDOC + AArch64 TLS LOCAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1 +ENUMDOC + AArch64 TLS LOCAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC +ENUMDOC + AArch64 TLS LOCAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2 +ENUMDOC + AArch64 TLS LOCAL EXEC relocation. +ENUM + BFD_RELOC_AARCH64_TLS_DTPMOD64 +ENUMDOC + AArch64 TLS relocation. +ENUM + BFD_RELOC_AARCH64_TLS_DTPREL64 +ENUMDOC + AArch64 TLS relocation. +ENUM + BFD_RELOC_AARCH64_TLS_TPREL64 +ENUMDOC + AArch64 TLS relocation. +ENUM + BFD_RELOC_AARCH64_TSTBR14 +ENUMDOC + AArch64 14 bit pc-relative test bit and branch. + The lowest two bits must be zero and are not stored in the instruction, + giving a 16 bit signed byte offset. ENUM BFD_RELOC_TILEPRO_COPY @@ -5777,6 +6453,18 @@ ENUMX BFD_RELOC_TILEPRO_SHAMT_Y0 ENUMX BFD_RELOC_TILEPRO_SHAMT_Y1 +ENUMX + BFD_RELOC_TILEPRO_TLS_GD_CALL +ENUMX + BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD +ENUMX + BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD +ENUMX + BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD +ENUMX + BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD +ENUMX + BFD_RELOC_TILEPRO_TLS_IE_LOAD ENUMX BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD ENUMX @@ -5815,9 +6503,24 @@ ENUMX BFD_RELOC_TILEPRO_TLS_DTPOFF32 ENUMX BFD_RELOC_TILEPRO_TLS_TPOFF32 +ENUMX + BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE +ENUMX + BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE +ENUMX + BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO +ENUMX + BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO +ENUMX + BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI +ENUMX + BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI +ENUMX + BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA +ENUMX + BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA ENUMDOC Tilera TILEPro Relocations. - ENUM BFD_RELOC_TILEGX_HW0 ENUMX @@ -5933,17 +6636,17 @@ ENUMX ENUMX BFD_RELOC_TILEGX_IMM16_X1_HW0_GOT ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW1_GOT + BFD_RELOC_TILEGX_IMM16_X0_HW0_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW1_GOT + BFD_RELOC_TILEGX_IMM16_X1_HW0_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW2_GOT + BFD_RELOC_TILEGX_IMM16_X0_HW1_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW2_GOT + BFD_RELOC_TILEGX_IMM16_X1_HW1_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW3_GOT + BFD_RELOC_TILEGX_IMM16_X0_HW2_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW3_GOT + BFD_RELOC_TILEGX_IMM16_X1_HW2_PLT_PCREL ENUMX BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_GOT ENUMX @@ -5953,25 +6656,25 @@ ENUMX ENUMX BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_GOT ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_GOT + BFD_RELOC_TILEGX_IMM16_X0_HW3_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_GOT + BFD_RELOC_TILEGX_IMM16_X1_HW3_PLT_PCREL ENUMX BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD ENUMX BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_GD + BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_GD + BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_GD + BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_GD + BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_GD + BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_GD + BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE ENUMX BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD ENUMX @@ -5980,26 +6683,22 @@ ENUMX BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD ENUMX BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD -ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_GD -ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_GD ENUMX BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE ENUMX BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_IE + BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_IE + BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_IE + BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_IE + BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_IE + BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_IE + BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL ENUMX BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE ENUMX @@ -6008,10 +6707,6 @@ ENUMX BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE ENUMX BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE -ENUMX - BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_IE -ENUMX - BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_IE ENUMX BFD_RELOC_TILEGX_TLS_DTPMOD64 ENUMX @@ -6024,9 +6719,28 @@ ENUMX BFD_RELOC_TILEGX_TLS_DTPOFF32 ENUMX BFD_RELOC_TILEGX_TLS_TPOFF32 +ENUMX + BFD_RELOC_TILEGX_TLS_GD_CALL +ENUMX + BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD +ENUMX + BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD +ENUMX + BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD +ENUMX + BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD +ENUMX + BFD_RELOC_TILEGX_TLS_IE_LOAD +ENUMX + BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD +ENUMX + BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD +ENUMX + BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD +ENUMX + BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD ENUMDOC Tilera TILE-Gx Relocations. - ENUM BFD_RELOC_EPIPHANY_SIMM8 ENUMDOC @@ -6210,23 +6924,26 @@ INTERNAL_FUNCTION bfd_generic_lookup_section_flags SYNOPSIS - void bfd_generic_lookup_section_flags - (struct bfd_link_info *, struct flag_info *); + bfd_boolean bfd_generic_lookup_section_flags + (struct bfd_link_info *, struct flag_info *, asection *); DESCRIPTION Provides default handling for section flags lookup -- i.e., does nothing. + Returns FALSE if the section should be omitted, otherwise TRUE. */ -void +bfd_boolean bfd_generic_lookup_section_flags (struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct flag_info *finfo) + struct flag_info *flaginfo, + asection *section ATTRIBUTE_UNUSED) { - if (finfo != NULL) + if (flaginfo != NULL) { (*_bfd_error_handler) (_("INPUT_SECTION_FLAGS are not supported.\n")); - return; + return FALSE; } + return TRUE; } /* @@ -6314,7 +7031,7 @@ bfd_generic_get_relocated_section_contents (bfd *abfd, bfd_reloc_status_type r; symbol = *(*parent)->sym_ptr_ptr; - if (symbol->section && elf_discarded_section (symbol->section)) + if (symbol->section && discarded_section (symbol->section)) { bfd_byte *p; static reloc_howto_type none_howto @@ -6324,7 +7041,7 @@ bfd_generic_get_relocated_section_contents (bfd *abfd, p = data + (*parent)->address * bfd_octets_per_byte (input_bfd); _bfd_clear_contents ((*parent)->howto, input_bfd, input_section, p); - (*parent)->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; + (*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; (*parent)->addend = 0; (*parent)->howto = &none_howto; r = bfd_reloc_ok; @@ -6373,6 +7090,15 @@ bfd_generic_get_relocated_section_contents (bfd *abfd, goto error_return; break; case bfd_reloc_outofrange: + /* PR ld/13730: + This error can result when processing some partially + complete binaries. Do not abort, but issue an error + message instead. */ + link_info->callbacks->einfo + (_("%X%P: %B(%A): relocation \"%R\" goes out of range\n"), + abfd, input_section, * parent); + goto error_return; + default: abort (); break; diff --git a/contrib/gdb-7/bfd/section.c b/contrib/gdb-7/bfd/section.c index 7c1f750483..fb19d8cc3a 100644 --- a/contrib/gdb-7/bfd/section.c +++ b/contrib/gdb-7/bfd/section.c @@ -1,6 +1,7 @@ /* Object file "section" support for the BFD library. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012, 2013 Free Software Foundation, Inc. Written by Cygnus Support. @@ -382,11 +383,11 @@ CODE_FRAGMENT . . {* Type of sec_info information. *} . unsigned int sec_info_type:3; -.#define ELF_INFO_TYPE_NONE 0 -.#define ELF_INFO_TYPE_STABS 1 -.#define ELF_INFO_TYPE_MERGE 2 -.#define ELF_INFO_TYPE_EH_FRAME 3 -.#define ELF_INFO_TYPE_JUST_SYMS 4 +.#define SEC_INFO_TYPE_NONE 0 +.#define SEC_INFO_TYPE_STABS 1 +.#define SEC_INFO_TYPE_MERGE 2 +.#define SEC_INFO_TYPE_EH_FRAME 3 +.#define SEC_INFO_TYPE_JUST_SYMS 4 . . {* Nonzero if this section uses RELA relocations, rather than REL. *} . unsigned int use_rela_p:1; @@ -516,9 +517,6 @@ CODE_FRAGMENT . {* The BFD which owns the section. *} . bfd *owner; . -. {* INPUT_SECTION_FLAGS if specified in the linker script. *} -. struct flag_info *section_flag_info; -. . {* A symbol which points at this section only. *} . struct bfd_symbol *symbol; . struct bfd_symbol **symbol_ptr_ptr; @@ -534,40 +532,37 @@ CODE_FRAGMENT .} asection; . .{* Relax table contains information about instructions which can -. be removed by relaxation -- replacing a long address with a +. be removed by relaxation -- replacing a long address with a . short address. *} .struct relax_table { . {* Address where bytes may be deleted. *} . bfd_vma addr; -. +. . {* Number of bytes to be deleted. *} . int size; .}; . .{* These sections are global, and are managed by BFD. The application . and target back end are not permitted to change the values in -. these sections. New code should use the section_ptr macros rather -. than referring directly to the const sections. The const sections -. may eventually vanish. *} +. these sections. *} +.extern asection _bfd_std_section[4]; +. .#define BFD_ABS_SECTION_NAME "*ABS*" .#define BFD_UND_SECTION_NAME "*UND*" .#define BFD_COM_SECTION_NAME "*COM*" .#define BFD_IND_SECTION_NAME "*IND*" . -.{* The absolute section. *} -.extern asection bfd_abs_section; -.#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) -.#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) -.{* Pointer to the undefined section. *} -.extern asection bfd_und_section; -.#define bfd_und_section_ptr ((asection *) &bfd_und_section) -.#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) .{* Pointer to the common section. *} -.extern asection bfd_com_section; -.#define bfd_com_section_ptr ((asection *) &bfd_com_section) +.#define bfd_com_section_ptr (&_bfd_std_section[0]) +.{* Pointer to the undefined section. *} +.#define bfd_und_section_ptr (&_bfd_std_section[1]) +.{* Pointer to the absolute section. *} +.#define bfd_abs_section_ptr (&_bfd_std_section[2]) .{* Pointer to the indirect section. *} -.extern asection bfd_ind_section; -.#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) +.#define bfd_ind_section_ptr (&_bfd_std_section[3]) +. +.#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) +.#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) .#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) . .#define bfd_is_const_section(SEC) \ @@ -682,8 +677,8 @@ CODE_FRAGMENT . {* vma, lma, size, rawsize, compressed_size, relax, relax_count, *} \ . 0, 0, 0, 0, 0, 0, 0, \ . \ -. {* output_offset, output_section, alignment_power, *} \ -. 0, (struct bfd_section *) &SEC, 0, \ +. {* output_offset, output_section, alignment_power, *} \ +. 0, &SEC, 0, \ . \ . {* relocation, orelocation, reloc_count, filepos, rel_filepos, *} \ . NULL, NULL, 0, 0, 0, \ @@ -697,9 +692,6 @@ CODE_FRAGMENT . {* target_index, used_by_bfd, constructor_chain, owner, *} \ . 0, NULL, NULL, NULL, \ . \ -. {* flag_info, *} \ -. NULL, \ -. \ . {* symbol, symbol_ptr_ptr, *} \ . (struct bfd_symbol *) SYM, &SEC.symbol, \ . \ @@ -715,10 +707,10 @@ CODE_FRAGMENT /* the_bfd, name, value, attr, section [, udata] */ #ifdef __STDC__ #define GLOBAL_SYM_INIT(NAME, SECTION) \ - { 0, NAME, 0, BSF_SECTION_SYM, (asection *) SECTION, { 0 }} + { 0, NAME, 0, BSF_SECTION_SYM, SECTION, { 0 }} #else #define GLOBAL_SYM_INIT(NAME, SECTION) \ - { 0, NAME, 0, BSF_SECTION_SYM, (asection *) SECTION } + { 0, NAME, 0, BSF_SECTION_SYM, SECTION } #endif /* These symbols are global, not specific to any BFD. Therefore, anything @@ -726,20 +718,21 @@ CODE_FRAGMENT static const asymbol global_syms[] = { - GLOBAL_SYM_INIT (BFD_COM_SECTION_NAME, &bfd_com_section), - GLOBAL_SYM_INIT (BFD_UND_SECTION_NAME, &bfd_und_section), - GLOBAL_SYM_INIT (BFD_ABS_SECTION_NAME, &bfd_abs_section), - GLOBAL_SYM_INIT (BFD_IND_SECTION_NAME, &bfd_ind_section) + GLOBAL_SYM_INIT (BFD_COM_SECTION_NAME, bfd_com_section_ptr), + GLOBAL_SYM_INIT (BFD_UND_SECTION_NAME, bfd_und_section_ptr), + GLOBAL_SYM_INIT (BFD_ABS_SECTION_NAME, bfd_abs_section_ptr), + GLOBAL_SYM_INIT (BFD_IND_SECTION_NAME, bfd_ind_section_ptr) }; -#define STD_SECTION(SEC, FLAGS, NAME, IDX) \ - asection SEC = BFD_FAKE_SECTION(SEC, FLAGS, &global_syms[IDX], \ - NAME, IDX) +#define STD_SECTION(NAME, IDX, FLAGS) \ + BFD_FAKE_SECTION(_bfd_std_section[IDX], FLAGS, &global_syms[IDX], NAME, IDX) -STD_SECTION (bfd_com_section, SEC_IS_COMMON, BFD_COM_SECTION_NAME, 0); -STD_SECTION (bfd_und_section, 0, BFD_UND_SECTION_NAME, 1); -STD_SECTION (bfd_abs_section, 0, BFD_ABS_SECTION_NAME, 2); -STD_SECTION (bfd_ind_section, 0, BFD_IND_SECTION_NAME, 3); +asection _bfd_std_section[] = { + STD_SECTION (BFD_COM_SECTION_NAME, 0, SEC_IS_COMMON), + STD_SECTION (BFD_UND_SECTION_NAME, 1, 0), + STD_SECTION (BFD_ABS_SECTION_NAME, 2, 0), + STD_SECTION (BFD_IND_SECTION_NAME, 3, 0) +}; #undef STD_SECTION /* Initialize an entry in the section hash table. */ @@ -842,6 +835,7 @@ bfd_section_list_clear (bfd *abfd) abfd->section_count = 0; memset (abfd->section_htab.table, 0, abfd->section_htab.size * sizeof (struct bfd_hash_entry *)); + abfd->section_htab.count = 0; } /* @@ -852,14 +846,8 @@ SYNOPSIS asection *bfd_get_section_by_name (bfd *abfd, const char *name); DESCRIPTION - Run through @var{abfd} and return the one of the - <>s whose name matches @var{name}, otherwise <>. - @xref{Sections}, for more information. - - This should only be used in special cases; the normal way to process - all sections of a given name is to use <> and - <> on the name (or better yet, base it on the section flags - or something else) for each section. + Return the most recently created section attached to @var{abfd} + named @var{name}. Return NULL if no such section exists. */ asection * @@ -874,6 +862,63 @@ bfd_get_section_by_name (bfd *abfd, const char *name) return NULL; } +/* +FUNCTION + bfd_get_next_section_by_name + +SYNOPSIS + asection *bfd_get_next_section_by_name (asection *sec); + +DESCRIPTION + Given @var{sec} is a section returned by @code{bfd_get_section_by_name}, + return the next most recently created section attached to the same + BFD with the same name. Return NULL if no such section exists. +*/ + +asection * +bfd_get_next_section_by_name (asection *sec) +{ + struct section_hash_entry *sh; + const char *name; + unsigned long hash; + + sh = ((struct section_hash_entry *) + ((char *) sec - offsetof (struct section_hash_entry, section))); + + hash = sh->root.hash; + name = sec->name; + for (sh = (struct section_hash_entry *) sh->root.next; + sh != NULL; + sh = (struct section_hash_entry *) sh->root.next) + if (sh->root.hash == hash + && strcmp (sh->root.string, name) == 0) + return &sh->section; + + return NULL; +} + +/* +FUNCTION + bfd_get_linker_section + +SYNOPSIS + asection *bfd_get_linker_section (bfd *abfd, const char *name); + +DESCRIPTION + Return the linker created section attached to @var{abfd} + named @var{name}. Return NULL if no such section exists. +*/ + +asection * +bfd_get_linker_section (bfd *abfd, const char *name) +{ + asection *sec = bfd_get_section_by_name (abfd, name); + + while (sec != NULL && (sec->flags & SEC_LINKER_CREATED) == 0) + sec = bfd_get_next_section_by_name (sec); + return sec; +} + /* FUNCTION bfd_get_section_by_name_if @@ -1267,7 +1312,7 @@ DESCRIPTION This is the preferred method for iterating over sections; an alternative would be to use a loop: -| section *p; +| asection *p; | for (p = abfd->sections; p != NULL; p = p->next) | func (abfd, p, ...) @@ -1501,8 +1546,8 @@ bfd_get_section_contents (bfd *abfd, bfd_set_error (bfd_error_invalid_operation); return FALSE; } - - memcpy (location, section->contents + offset, (size_t) count); + + memmove (location, section->contents + offset, (size_t) count); return TRUE; } diff --git a/contrib/gdb-7/bfd/stab-syms.c b/contrib/gdb-7/bfd/stab-syms.c index 9e9274f987..8e65ddc65c 100644 --- a/contrib/gdb-7/bfd/stab-syms.c +++ b/contrib/gdb-7/bfd/stab-syms.c @@ -1,5 +1,5 @@ /* Table of stab names for the BFD library. - Copyright 1990, 1991, 1992, 1994, 1995, 1996, 2000, 2005, 2007 + Copyright 1990, 1991, 1992, 1994, 1995, 1996, 2000, 2005, 2007, 2012 Free Software Foundation, Inc. Written by Cygnus Support. @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "sysdep.h" #include "bfd.h" #define ARCH_SIZE 32 /* Value doesn't matter. */ diff --git a/contrib/gdb-7/bfd/syms.c b/contrib/gdb-7/bfd/syms.c index e819eae16d..98d596ed44 100644 --- a/contrib/gdb-7/bfd/syms.c +++ b/contrib/gdb-7/bfd/syms.c @@ -1,6 +1,6 @@ /* Generic symbol-table support for the BFD library. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2012 Free Software Foundation, Inc. Written by Cygnus Support. @@ -77,7 +77,7 @@ SUBSECTION | | if (storage_needed == 0) | return; -| +| | symbol_table = xmalloc (storage_needed); | ... | number_of_symbols = @@ -107,6 +107,7 @@ SUBSECTION which has been created using <>. Here is an example showing the creation of a symbol table with only one element: +| #include "sysdep.h" | #include "bfd.h" | int main (void) | { @@ -1007,7 +1008,7 @@ _bfd_stab_section_find_nearest_line (bfd *abfd, /* Try SOM section names. */ info->stabsec = bfd_get_section_by_name (abfd, "$GDB_SYMBOLS$"); info->strsec = bfd_get_section_by_name (abfd, "$GDB_STRINGS$"); - + if (info->stabsec == NULL || info->strsec == NULL) { /* No stabs debugging information. Set *pinfo so that we diff --git a/contrib/gdb-7/bfd/sysdep.h b/contrib/gdb-7/bfd/sysdep.h index 20ef56d69a..b4fed10441 100644 --- a/contrib/gdb-7/bfd/sysdep.h +++ b/contrib/gdb-7/bfd/sysdep.h @@ -23,6 +23,10 @@ #ifndef BFD_SYSDEP_H #define BFD_SYSDEP_H +#ifdef PACKAGE +#error sysdep.h must be included in lieu of config.h +#endif + #include "config.h" #include "ansidecl.h" diff --git a/contrib/gdb-7/bfd/targets.c b/contrib/gdb-7/bfd/targets.c index 4cf8e8fb32..c9fbbc2fe3 100644 --- a/contrib/gdb-7/bfd/targets.c +++ b/contrib/gdb-7/bfd/targets.c @@ -1,6 +1,6 @@ /* Generic target-file-type support for the BFD library. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Written by Cygnus Support. @@ -369,6 +369,7 @@ BFD_JUMP_TABLE macros. . NAME##_bfd_is_target_special_symbol, \ . NAME##_get_lineno, \ . NAME##_find_nearest_line, \ +. _bfd_generic_find_nearest_line_discriminator, \ . _bfd_generic_find_line, \ . NAME##_find_inliner_info, \ . NAME##_bfd_make_debug_symbol, \ @@ -392,6 +393,9 @@ BFD_JUMP_TABLE macros. . bfd_boolean (*_bfd_find_nearest_line) . (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, . const char **, const char **, unsigned int *); +. bfd_boolean (*_bfd_find_nearest_line_discriminator) +. (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, +. const char **, const char **, unsigned int *, unsigned int *); . bfd_boolean (*_bfd_find_line) . (bfd *, struct bfd_symbol **, struct bfd_symbol *, . const char **, unsigned int *); @@ -497,8 +501,9 @@ BFD_JUMP_TABLE macros. . bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); . . {* Sets the bitmask of allowed and disallowed section flags. *} -. void (*_bfd_lookup_section_flags) (struct bfd_link_info *, -. struct flag_info *); +. bfd_boolean (*_bfd_lookup_section_flags) (struct bfd_link_info *, +. struct flag_info *, +. asection *); . . {* Attempt to merge SEC_MERGE sections. *} . bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); @@ -596,10 +601,13 @@ extern const bfd_target bfd_elf32_bfinfdpic_vec; extern const bfd_target bfd_elf32_big_generic_vec; extern const bfd_target bfd_elf32_bigarc_vec; extern const bfd_target bfd_elf32_bigarm_vec; +extern const bfd_target bfd_elf32_bigarm_nacl_vec; extern const bfd_target bfd_elf32_bigarm_symbian_vec; extern const bfd_target bfd_elf32_bigarm_vxworks_vec; extern const bfd_target bfd_elf32_bigmips_vec; extern const bfd_target bfd_elf32_bigmips_vxworks_vec; +extern const bfd_target bfd_elf32_bigmoxie_vec; +extern const bfd_target bfd_elf32_bignios2_vec; extern const bfd_target bfd_elf32_cr16_vec; extern const bfd_target bfd_elf32_cr16c_vec; extern const bfd_target bfd_elf32_cris_vec; @@ -611,7 +619,6 @@ extern const bfd_target bfd_elf32_epiphany_vec; extern const bfd_target bfd_elf32_fr30_vec; extern const bfd_target bfd_elf32_frv_vec; extern const bfd_target bfd_elf32_frvfdpic_vec; -extern const bfd_target bfd_elf32_moxie_vec; extern const bfd_target bfd_elf32_h8300_vec; extern const bfd_target bfd_elf32_hppa_linux_vec; extern const bfd_target bfd_elf32_hppa_nbsd_vec; @@ -634,10 +641,13 @@ extern const bfd_target bfd_elf32_lm32fdpic_vec; extern const bfd_target bfd_elf32_little_generic_vec; extern const bfd_target bfd_elf32_littlearc_vec; extern const bfd_target bfd_elf32_littlearm_vec; +extern const bfd_target bfd_elf32_littlearm_nacl_vec; extern const bfd_target bfd_elf32_littlearm_symbian_vec; extern const bfd_target bfd_elf32_littlearm_vxworks_vec; extern const bfd_target bfd_elf32_littlemips_vec; extern const bfd_target bfd_elf32_littlemips_vxworks_vec; +extern const bfd_target bfd_elf32_littlemoxie_vec; +extern const bfd_target bfd_elf32_littlenios2_vec; extern const bfd_target bfd_elf32_m32c_vec; extern const bfd_target bfd_elf32_m32r_vec; extern const bfd_target bfd_elf32_m32rle_vec; @@ -651,6 +661,8 @@ extern const bfd_target bfd_elf32_mcore_big_vec; extern const bfd_target bfd_elf32_mcore_little_vec; extern const bfd_target bfd_elf32_mep_vec; extern const bfd_target bfd_elf32_mep_little_vec; +extern const bfd_target bfd_elf32_metag_vec; +extern const bfd_target bfd_elf32_microblazeel_vec; extern const bfd_target bfd_elf32_microblaze_vec; extern const bfd_target bfd_elf32_mn10200_vec; extern const bfd_target bfd_elf32_mn10300_vec; @@ -704,7 +716,8 @@ extern const bfd_target bfd_elf32_tic6x_elf_be_vec; extern const bfd_target bfd_elf32_tic6x_elf_le_vec; extern const bfd_target bfd_elf32_tic6x_linux_be_vec; extern const bfd_target bfd_elf32_tic6x_linux_le_vec; -extern const bfd_target bfd_elf32_tilegx_vec; +extern const bfd_target bfd_elf32_tilegx_be_vec; +extern const bfd_target bfd_elf32_tilegx_le_vec; extern const bfd_target bfd_elf32_tilepro_vec; extern const bfd_target bfd_elf32_tradbigmips_vec; extern const bfd_target bfd_elf32_tradlittlemips_vec; @@ -712,8 +725,10 @@ extern const bfd_target bfd_elf32_tradbigmips_freebsd_vec; extern const bfd_target bfd_elf32_tradlittlemips_freebsd_vec; extern const bfd_target bfd_elf32_us_cris_vec; extern const bfd_target bfd_elf32_v850_vec; +extern const bfd_target bfd_elf32_v850_rh850_vec; extern const bfd_target bfd_elf32_vax_vec; extern const bfd_target bfd_elf32_xc16x_vec; +extern const bfd_target bfd_elf32_xgate_vec; extern const bfd_target bfd_elf32_xstormy16_vec; extern const bfd_target bfd_elf32_xtensa_be_vec; extern const bfd_target bfd_elf32_xtensa_le_vec; @@ -721,6 +736,7 @@ extern const bfd_target bfd_elf64_alpha_freebsd_vec; extern const bfd_target bfd_elf64_alpha_vec; extern const bfd_target bfd_elf64_big_generic_vec; extern const bfd_target bfd_elf64_bigmips_vec; +extern const bfd_target bfd_elf64_bigaarch64_vec; extern const bfd_target bfd_elf64_hppa_linux_vec; extern const bfd_target bfd_elf64_hppa_vec; extern const bfd_target bfd_elf64_ia64_big_vec; @@ -729,6 +745,7 @@ extern const bfd_target bfd_elf64_ia64_little_vec; extern const bfd_target bfd_elf64_ia64_vms_vec; extern const bfd_target bfd_elf64_little_generic_vec; extern const bfd_target bfd_elf64_littlemips_vec; +extern const bfd_target bfd_elf64_littleaarch64_vec; extern const bfd_target bfd_elf64_mmix_vec; extern const bfd_target bfd_elf64_powerpc_vec; extern const bfd_target bfd_elf64_powerpcle_vec; @@ -743,14 +760,17 @@ extern const bfd_target bfd_elf64_sh64nbsd_vec; extern const bfd_target bfd_elf64_sparc_vec; extern const bfd_target bfd_elf64_sparc_freebsd_vec; extern const bfd_target bfd_elf64_sparc_sol2_vec; -extern const bfd_target bfd_elf64_tilegx_vec; +extern const bfd_target bfd_elf64_tilegx_be_vec; +extern const bfd_target bfd_elf64_tilegx_le_vec; extern const bfd_target bfd_elf64_tradbigmips_vec; extern const bfd_target bfd_elf64_tradlittlemips_vec; extern const bfd_target bfd_elf64_tradbigmips_freebsd_vec; extern const bfd_target bfd_elf64_tradlittlemips_freebsd_vec; extern const bfd_target bfd_elf64_x86_64_freebsd_vec; +extern const bfd_target bfd_elf64_x86_64_nacl_vec; extern const bfd_target bfd_elf64_x86_64_sol2_vec; extern const bfd_target bfd_elf64_x86_64_vec; +extern const bfd_target bfd_elf32_x86_64_nacl_vec; extern const bfd_target bfd_elf32_x86_64_vec; extern const bfd_target bfd_elf64_l1om_freebsd_vec; extern const bfd_target bfd_elf64_l1om_vec; @@ -965,6 +985,8 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf32_bigarm_vxworks_vec, &bfd_elf32_bigmips_vec, &bfd_elf32_bigmips_vxworks_vec, + &bfd_elf32_bigmoxie_vec, + &bfd_elf32_bignios2_vec, &bfd_elf32_cr16_vec, &bfd_elf32_cr16c_vec, &bfd_elf32_cris_vec, @@ -976,7 +998,6 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf32_fr30_vec, &bfd_elf32_frv_vec, &bfd_elf32_frvfdpic_vec, - &bfd_elf32_moxie_vec, &bfd_elf32_h8300_vec, &bfd_elf32_hppa_linux_vec, &bfd_elf32_hppa_nbsd_vec, @@ -1006,6 +1027,8 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf32_littlearm_vxworks_vec, &bfd_elf32_littlemips_vec, &bfd_elf32_littlemips_vxworks_vec, + &bfd_elf32_littlemoxie_vec, + &bfd_elf32_littlenios2_vec, &bfd_elf32_m32c_vec, &bfd_elf32_m32r_vec, &bfd_elf32_m32rle_vec, @@ -1018,6 +1041,7 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf32_mcore_big_vec, &bfd_elf32_mcore_little_vec, &bfd_elf32_mep_vec, + &bfd_elf32_metag_vec, &bfd_elf32_microblaze_vec, &bfd_elf32_mn10200_vec, &bfd_elf32_mn10300_vec, @@ -1073,7 +1097,8 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf32_spu_vec, &bfd_elf32_tic6x_be_vec, &bfd_elf32_tic6x_le_vec, - &bfd_elf32_tilegx_vec, + &bfd_elf32_tilegx_be_vec, + &bfd_elf32_tilegx_le_vec, &bfd_elf32_tilepro_vec, &bfd_elf32_tradbigmips_vec, &bfd_elf32_tradlittlemips_vec, @@ -1081,8 +1106,10 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf32_tradlittlemips_freebsd_vec, &bfd_elf32_us_cris_vec, &bfd_elf32_v850_vec, + &bfd_elf32_v850_rh850_vec, &bfd_elf32_vax_vec, &bfd_elf32_xc16x_vec, + &bfd_elf32_xgate_vec, &bfd_elf32_xstormy16_vec, &bfd_elf32_xtensa_be_vec, &bfd_elf32_xtensa_le_vec, @@ -1091,6 +1118,7 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf64_alpha_vec, &bfd_elf64_big_generic_vec, &bfd_elf64_bigmips_vec, + &bfd_elf64_bigaarch64_vec, &bfd_elf64_hppa_linux_vec, &bfd_elf64_hppa_vec, &bfd_elf64_ia64_big_vec, @@ -1099,6 +1127,7 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf64_ia64_vms_vec, &bfd_elf64_little_generic_vec, &bfd_elf64_littlemips_vec, + &bfd_elf64_littleaarch64_vec, &bfd_elf64_mmix_vec, &bfd_elf64_powerpc_vec, &bfd_elf64_powerpcle_vec, @@ -1113,14 +1142,17 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf64_sparc_vec, &bfd_elf64_sparc_freebsd_vec, &bfd_elf64_sparc_sol2_vec, - &bfd_elf64_tilegx_vec, + &bfd_elf64_tilegx_be_vec, + &bfd_elf64_tilegx_le_vec, &bfd_elf64_tradbigmips_vec, &bfd_elf64_tradlittlemips_vec, &bfd_elf64_tradbigmips_freebsd_vec, &bfd_elf64_tradlittlemips_freebsd_vec, &bfd_elf64_x86_64_freebsd_vec, + &bfd_elf64_x86_64_nacl_vec, &bfd_elf64_x86_64_sol2_vec, &bfd_elf64_x86_64_vec, + &bfd_elf32_x86_64_nacl_vec, &bfd_elf32_x86_64_vec, &bfd_elf64_l1om_freebsd_vec, &bfd_elf64_l1om_vec, diff --git a/contrib/gdb-7/bfd/tekhex.c b/contrib/gdb-7/bfd/tekhex.c index 0ed7b5032b..c52eb95329 100644 --- a/contrib/gdb-7/bfd/tekhex.c +++ b/contrib/gdb-7/bfd/tekhex.c @@ -297,7 +297,7 @@ getsym (char *dstp, char **srcp, unsigned int *lenp) char *src = *srcp; unsigned int i; unsigned int len; - + if (!ISHEX (*src)) return FALSE; diff --git a/contrib/gdb-7/bfd/version.h b/contrib/gdb-7/bfd/version.h index f2460949ad..97ac40d177 100644 --- a/contrib/gdb-7/bfd/version.h +++ b/contrib/gdb-7/bfd/version.h @@ -1,4 +1,4 @@ -#define BFD_VERSION_DATE 20111213 +#define BFD_VERSION_DATE 20130312 #define BFD_VERSION @bfd_version@ #define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@ #define REPORT_BUGS_TO @report_bugs_to@ diff --git a/contrib/gdb-7/gdb/README b/contrib/gdb-7/gdb/README index 999f9927f6..33516ac9ea 100644 --- a/contrib/gdb-7/gdb/README +++ b/contrib/gdb-7/gdb/README @@ -446,10 +446,10 @@ prefer; but you may abbreviate option names if you use `--'. Build GDB with the gdbtk GUI interface. Requires TCL/Tk to be installed. -`--with-libunwind' - Use the libunwind library for unwinding function call stack. See - http://www.nongnu.org/libunwind/index.html fro details. - Supported only on some platforms. +`--with-libunwind-ia64' + Use the libunwind library for unwinding function call stack on ia64 + target platforms. + See http://www.nongnu.org/libunwind/index.html for details. `--with-curses' Use the curses library instead of the termcap library, for diff --git a/contrib/gdb-7/gdb/ada-exp.c b/contrib/gdb-7/gdb/ada-exp.c new file mode 100644 index 0000000000..e83ae8654e --- /dev/null +++ b/contrib/gdb-7/gdb/ada-exp.c @@ -0,0 +1,3784 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 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 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 . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 36 "ada-exp.y" + + +#include "defs.h" +#include "gdb_string.h" +#include +#include "expression.h" +#include "value.h" +#include "parser-defs.h" +#include "language.h" +#include "ada-lang.h" +#include "bfd.h" /* Required by objfiles.h. */ +#include "symfile.h" /* Required by objfiles.h. */ +#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */ +#include "frame.h" +#include "block.h" + +#define parse_type builtin_type (parse_gdbarch) + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. These are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +/* NOTE: This is clumsy, especially since BISON and FLEX provide --prefix + options. I presume we are maintaining it to accommodate systems + without BISON? (PNH) */ + +#define yymaxdepth ada_maxdepth +#define yyparse _ada_parse /* ada_parse calls this after initialization */ +#define yylex ada_lex +#define yyerror ada_error +#define yylval ada_lval +#define yychar ada_char +#define yydebug ada_debug +#define yypact ada_pact +#define yyr1 ada_r1 +#define yyr2 ada_r2 +#define yydef ada_def +#define yychk ada_chk +#define yypgo ada_pgo +#define yyact ada_act +#define yyexca ada_exca +#define yyerrflag ada_errflag +#define yynerrs ada_nerrs +#define yyps ada_ps +#define yypv ada_pv +#define yys ada_s +#define yy_yys ada_yys +#define yystate ada_state +#define yytmp ada_tmp +#define yyv ada_v +#define yy_yyv ada_yyv +#define yyval ada_val +#define yylloc ada_lloc +#define yyreds ada_reds /* With YYDEBUG defined */ +#define yytoks ada_toks /* With YYDEBUG defined */ +#define yyname ada_name /* With YYDEBUG defined */ +#define yyrule ada_rule /* With YYDEBUG defined */ +#define yyss ada_yyss +#define yysslim ada_yysslim +#define yyssp ada_yyssp +#define yystacksize ada_yystacksize +#define yyvs ada_yyvs +#define yyvsp ada_yyvsp + +#ifndef YYDEBUG +#define YYDEBUG 1 /* Default to yydebug support */ +#endif + +#define YYFPRINTF parser_fprintf + +struct name_info { + struct symbol *sym; + struct minimal_symbol *msym; + struct block *block; + struct stoken stoken; +}; + +static struct stoken empty_stoken = { "", 0 }; + +/* If expression is in the context of TYPE'(...), then TYPE, else + * NULL. */ +static struct type *type_qualifier; + +int yyparse (void); + +static int yylex (void); + +void yyerror (char *); + +static struct stoken string_to_operator (struct stoken); + +static void write_int (LONGEST, struct type *); + +static void write_object_renaming (const struct block *, const char *, int, + const char *, int); + +static struct type* write_var_or_type (const struct block *, struct stoken); + +static void write_name_assoc (struct stoken); + +static void write_exp_op_with_string (enum exp_opcode, struct stoken); + +static struct block *block_lookup (struct block *, char *); + +static LONGEST convert_char_literal (struct type *, LONGEST); + +static void write_ambiguous_var (const struct block *, char *, int); + +static struct type *type_int (void); + +static struct type *type_long (void); + +static struct type *type_long_long (void); + +static struct type *type_float (void); + +static struct type *type_double (void); + +static struct type *type_long_double (void); + +static struct type *type_char (void); + +static struct type *type_boolean (void); + +static struct type *type_system_address (void); + + + +/* Line 189 of yacc.c */ +#line 205 "ada-exp.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + INT = 258, + NULL_PTR = 259, + CHARLIT = 260, + FLOAT = 261, + TRUEKEYWORD = 262, + FALSEKEYWORD = 263, + COLONCOLON = 264, + STRING = 265, + NAME = 266, + DOT_ID = 267, + DOT_ALL = 268, + SPECIAL_VARIABLE = 269, + ASSIGN = 270, + ELSE = 271, + THEN = 272, + XOR = 273, + OR = 274, + _AND_ = 275, + DOTDOT = 276, + IN = 277, + GEQ = 278, + LEQ = 279, + NOTEQUAL = 280, + UNARY = 281, + REM = 282, + MOD = 283, + NOT = 284, + ABS = 285, + STARSTAR = 286, + VAR = 287, + ARROW = 288, + TICK_LENGTH = 289, + TICK_LAST = 290, + TICK_FIRST = 291, + TICK_ADDRESS = 292, + TICK_ACCESS = 293, + TICK_MODULUS = 294, + TICK_MIN = 295, + TICK_MAX = 296, + TICK_VAL = 297, + TICK_TAG = 298, + TICK_SIZE = 299, + TICK_RANGE = 300, + TICK_POS = 301, + NEW = 302, + OTHERS = 303 + }; +#endif +/* Tokens. */ +#define INT 258 +#define NULL_PTR 259 +#define CHARLIT 260 +#define FLOAT 261 +#define TRUEKEYWORD 262 +#define FALSEKEYWORD 263 +#define COLONCOLON 264 +#define STRING 265 +#define NAME 266 +#define DOT_ID 267 +#define DOT_ALL 268 +#define SPECIAL_VARIABLE 269 +#define ASSIGN 270 +#define ELSE 271 +#define THEN 272 +#define XOR 273 +#define OR 274 +#define _AND_ 275 +#define DOTDOT 276 +#define IN 277 +#define GEQ 278 +#define LEQ 279 +#define NOTEQUAL 280 +#define UNARY 281 +#define REM 282 +#define MOD 283 +#define NOT 284 +#define ABS 285 +#define STARSTAR 286 +#define VAR 287 +#define ARROW 288 +#define TICK_LENGTH 289 +#define TICK_LAST 290 +#define TICK_FIRST 291 +#define TICK_ADDRESS 292 +#define TICK_ACCESS 293 +#define TICK_MODULUS 294 +#define TICK_MIN 295 +#define TICK_MAX 296 +#define TICK_VAL 297 +#define TICK_TAG 298 +#define TICK_SIZE 299 +#define TICK_RANGE 300 +#define TICK_POS 301 +#define NEW 302 +#define OTHERS 303 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 168 "ada-exp.y" + + LONGEST lval; + struct { + LONGEST val; + struct type *type; + } typed_val; + struct { + DOUBLEST dval; + struct type *type; + } typed_val_float; + struct type *tval; + struct stoken sval; + struct block *bval; + struct internalvar *ivar; + + + +/* Line 214 of yacc.c */ +#line 355 "ada-exp.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 367 "ada-exp.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or xmalloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined xmalloc) \ + && (defined YYFREE || defined xfree))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC xmalloc +# if ! defined xmalloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *xmalloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE xfree +# if ! defined xfree && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void xfree (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 57 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 770 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 69 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 31 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 122 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 233 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 303 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 32, 64, + 58, 63, 34, 30, 65, 31, 57, 35, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, + 22, 21, 23, 2, 29, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 59, 2, 68, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 66, 42, 67, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 24, 25, 26, 27, + 28, 33, 36, 37, 38, 39, 40, 41, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 60, 61 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 7, 11, 15, 18, 21, 26, + 31, 32, 40, 41, 48, 55, 59, 61, 63, 65, + 67, 70, 73, 76, 79, 80, 82, 86, 90, 96, + 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, + 139, 143, 147, 151, 157, 163, 167, 174, 181, 186, + 190, 194, 198, 200, 202, 204, 206, 208, 210, 214, + 218, 223, 228, 232, 236, 241, 246, 250, 254, 257, + 260, 264, 268, 272, 275, 278, 286, 294, 300, 306, + 309, 310, 314, 316, 318, 319, 321, 323, 325, 327, + 329, 331, 333, 336, 338, 341, 344, 348, 351, 355, + 359, 361, 364, 367, 370, 374, 376, 378, 382, 386, + 388, 389, 394, 398, 399, 406, 407, 412, 416, 417, + 424, 427, 430 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 70, 0, -1, 71, -1, 78, -1, 71, 62, 78, + -1, 72, 15, 78, -1, 72, 13, -1, 72, 12, + -1, 72, 58, 76, 63, -1, 87, 58, 76, 63, + -1, -1, 87, 64, 74, 73, 58, 78, 63, -1, + -1, 72, 58, 75, 24, 75, 63, -1, 87, 58, + 75, 24, 75, 63, -1, 58, 71, 63, -1, 87, + -1, 14, -1, 89, -1, 72, -1, 31, 75, -1, + 30, 75, -1, 38, 75, -1, 39, 75, -1, -1, + 78, -1, 11, 43, 78, -1, 76, 65, 78, -1, + 76, 65, 11, 43, 78, -1, 66, 87, 67, 72, + -1, 75, 40, 75, -1, 75, 34, 75, -1, 75, + 35, 75, -1, 75, 36, 75, -1, 75, 37, 75, + -1, 75, 29, 75, -1, 75, 30, 75, -1, 75, + 32, 75, -1, 75, 31, 75, -1, 75, -1, 75, + 21, 75, -1, 75, 28, 75, -1, 75, 27, 75, + -1, 75, 25, 75, 24, 75, -1, 75, 25, 72, + 55, 84, -1, 75, 25, 87, -1, 75, 38, 25, + 75, 24, 75, -1, 75, 38, 25, 72, 55, 84, + -1, 75, 38, 25, 87, -1, 75, 26, 75, -1, + 75, 22, 75, -1, 75, 23, 75, -1, 77, -1, + 79, -1, 80, -1, 81, -1, 82, -1, 83, -1, + 77, 20, 77, -1, 79, 20, 77, -1, 77, 20, + 17, 77, -1, 80, 20, 17, 77, -1, 77, 19, + 77, -1, 81, 19, 77, -1, 77, 19, 16, 77, + -1, 82, 19, 16, 77, -1, 77, 18, 77, -1, + 83, 18, 77, -1, 72, 48, -1, 72, 47, -1, + 72, 46, 84, -1, 72, 45, 84, -1, 72, 44, + 84, -1, 72, 54, -1, 72, 53, -1, 86, 50, + 58, 78, 65, 78, 63, -1, 86, 51, 58, 78, + 65, 78, 63, -1, 86, 56, 58, 78, 63, -1, + 85, 52, 58, 78, 63, -1, 85, 49, -1, -1, + 58, 3, 63, -1, 87, -1, 85, -1, -1, 3, + -1, 5, -1, 6, -1, 4, -1, 10, -1, 7, + -1, 8, -1, 60, 11, -1, 11, -1, 88, 11, + -1, 11, 48, -1, 88, 11, 48, -1, 11, 9, + -1, 88, 11, 9, -1, 58, 90, 63, -1, 92, + -1, 91, 78, -1, 91, 92, -1, 78, 65, -1, + 91, 78, 65, -1, 93, -1, 94, -1, 94, 65, + 92, -1, 61, 43, 78, -1, 95, -1, -1, 11, + 43, 96, 78, -1, 75, 43, 78, -1, -1, 75, + 24, 75, 43, 97, 78, -1, -1, 11, 42, 98, + 95, -1, 75, 42, 95, -1, -1, 75, 24, 75, + 42, 99, 95, -1, 34, 72, -1, 32, 72, -1, + 72, 59, 78, 68, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 233, 233, 237, 238, 240, 245, 249, 253, 259, + 278, 278, 290, 294, 296, 304, 315, 325, 329, 332, + 335, 339, 343, 347, 351, 354, 356, 358, 360, 364, + 377, 381, 385, 389, 393, 397, 401, 405, 409, 413, + 416, 420, 424, 428, 430, 435, 443, 447, 453, 464, + 468, 472, 476, 477, 478, 479, 480, 481, 485, 487, + 492, 494, 499, 501, 506, 508, 512, 514, 526, 528, + 534, 537, 540, 543, 545, 547, 549, 551, 553, 555, + 559, 561, 566, 576, 578, 584, 588, 595, 603, 607, + 613, 615, 619, 623, 625, 627, 635, 646, 648, 653, + 662, 663, 669, 674, 680, 689, 690, 691, 695, 700, + 715, 714, 717, 720, 719, 725, 724, 727, 730, 729, + 737, 739, 741 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "INT", "NULL_PTR", "CHARLIT", "FLOAT", + "TRUEKEYWORD", "FALSEKEYWORD", "COLONCOLON", "STRING", "NAME", "DOT_ID", + "DOT_ALL", "SPECIAL_VARIABLE", "ASSIGN", "ELSE", "THEN", "XOR", "OR", + "_AND_", "'='", "'<'", "'>'", "DOTDOT", "IN", "GEQ", "LEQ", "NOTEQUAL", + "'@'", "'+'", "'-'", "'&'", "UNARY", "'*'", "'/'", "REM", "MOD", "NOT", + "ABS", "STARSTAR", "VAR", "'|'", "ARROW", "TICK_LENGTH", "TICK_LAST", + "TICK_FIRST", "TICK_ADDRESS", "TICK_ACCESS", "TICK_MODULUS", "TICK_MIN", + "TICK_MAX", "TICK_VAL", "TICK_TAG", "TICK_SIZE", "TICK_RANGE", + "TICK_POS", "'.'", "'('", "'['", "NEW", "OTHERS", "';'", "')'", "'\\''", + "','", "'{'", "'}'", "']'", "$accept", "start", "exp1", "primary", "$@1", + "save_qualifier", "simple_exp", "arglist", "relation", "exp", "and_exp", + "and_then_exp", "or_exp", "or_else_exp", "xor_exp", "tick_arglist", + "type_prefix", "opt_type_prefix", "var_or_type", "block", "aggregate", + "aggregate_component_list", "positional_list", "component_groups", + "others", "component_group", "component_associations", "$@2", "$@3", + "$@4", "$@5", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 61, 60, 62, 276, 277, 278, 279, 280, 64, + 43, 45, 38, 281, 42, 47, 282, 283, 284, 285, + 286, 287, 124, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 46, 40, 91, + 302, 303, 59, 41, 39, 44, 123, 125, 93 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 69, 70, 71, 71, 71, 72, 72, 72, 72, + 73, 72, 74, 72, 72, 72, 72, 72, 72, 75, + 75, 75, 75, 75, 76, 76, 76, 76, 76, 72, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 78, 78, 78, 78, 78, 78, 79, 79, + 80, 80, 81, 81, 82, 82, 83, 83, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 84, 84, 85, 86, 86, 72, 72, 72, 72, 72, + 72, 72, 72, 87, 87, 87, 87, 88, 88, 89, + 90, 90, 90, 91, 91, 92, 92, 92, 93, 94, + 96, 95, 95, 97, 95, 98, 95, 95, 99, 95, + 72, 72, 72 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 3, 3, 2, 2, 4, 4, + 0, 7, 0, 6, 6, 3, 1, 1, 1, 1, + 2, 2, 2, 2, 0, 1, 3, 3, 5, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, + 3, 3, 3, 5, 5, 3, 6, 6, 4, 3, + 3, 3, 1, 1, 1, 1, 1, 1, 3, 3, + 4, 4, 3, 3, 4, 4, 3, 3, 2, 2, + 3, 3, 3, 2, 2, 7, 7, 5, 5, 2, + 0, 3, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, + 1, 2, 2, 2, 3, 1, 1, 3, 3, 1, + 0, 4, 3, 0, 6, 0, 4, 3, 0, 6, + 2, 2, 4 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 84, 85, 88, 86, 87, 90, 91, 89, 93, 17, + 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, + 2, 19, 39, 52, 3, 53, 54, 55, 56, 57, + 83, 0, 16, 0, 18, 97, 95, 19, 21, 20, + 121, 120, 22, 23, 93, 0, 0, 39, 3, 0, + 84, 100, 105, 106, 109, 92, 0, 1, 84, 7, + 6, 84, 80, 80, 80, 69, 68, 74, 73, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 0, 84, 84, 84, + 84, 84, 0, 84, 0, 84, 79, 0, 0, 0, + 0, 84, 12, 94, 115, 110, 84, 15, 84, 84, + 84, 103, 99, 101, 102, 84, 84, 4, 5, 0, + 72, 71, 70, 93, 39, 0, 25, 0, 40, 50, + 51, 19, 0, 16, 49, 42, 41, 35, 36, 38, + 37, 31, 32, 33, 34, 84, 30, 66, 84, 62, + 84, 58, 59, 84, 63, 84, 67, 84, 84, 84, + 84, 39, 0, 10, 98, 96, 84, 84, 108, 0, + 0, 117, 112, 104, 107, 29, 0, 84, 84, 8, + 84, 122, 80, 84, 19, 0, 16, 64, 60, 61, + 65, 0, 0, 0, 0, 84, 9, 0, 116, 111, + 118, 113, 81, 26, 0, 93, 27, 44, 43, 80, + 84, 78, 84, 84, 77, 0, 84, 84, 84, 13, + 84, 47, 46, 0, 0, 14, 0, 119, 114, 28, + 75, 76, 11 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 19, 20, 37, 197, 163, 22, 125, 23, 126, + 25, 26, 27, 28, 29, 120, 30, 31, 32, 33, + 34, 49, 50, 51, 52, 53, 54, 167, 218, 166, + 217 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -104 +static const yytype_int16 yypact[] = +{ + 424, -104, -104, -104, -104, -104, -104, -104, 16, -104, + 424, 424, 118, 118, 424, 424, 286, -7, 6, 31, + -26, 501, 674, 20, -104, 28, 32, 22, 34, 42, + -44, -21, 84, 57, -104, -104, -104, 558, 63, 63, + -3, -3, 63, 63, 23, 26, -36, 611, 9, 27, + 286, -104, -104, 29, -104, -104, 25, -104, 424, -104, + -104, 424, 35, 35, 35, -104, -104, -104, -104, 274, + 424, 424, 424, 424, 424, 424, 424, 424, 424, 424, + 424, 424, 424, 424, 424, 424, 71, 424, 424, 350, + 387, 424, 91, 424, 85, 424, -104, 53, 58, 59, + 60, 274, -104, 19, -104, -104, 424, -104, 424, 461, + 424, -104, -104, 50, -104, 286, 118, -104, -104, 124, + -104, -104, -104, 3, 634, -52, -104, 70, 719, 719, + 719, 521, 166, 173, 719, 719, 719, 730, 63, 63, + 63, 99, 99, 99, 99, 424, 99, -104, 424, -104, + 424, -104, -104, 424, -104, 424, -104, 424, 424, 424, + 424, 654, -41, -104, -104, -104, 461, 424, -104, 704, + 689, -104, -104, -104, -104, -3, 68, 424, 424, -104, + 498, -104, 35, 424, 538, 215, 208, -104, -104, -104, + -104, 78, 79, 80, 83, 424, -104, 93, -104, -104, + -104, -104, -104, -104, 339, 14, -104, -104, 719, 35, + 424, -104, 424, 424, -104, 589, 424, 461, 424, -104, + 424, -104, 719, 90, 92, -104, 98, -104, -104, -104, + -104, -104, -104 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -104, -104, 127, 21, -104, -104, 4, 55, -46, 0, + -104, -104, -104, -104, -104, -62, -104, -104, -15, -104, + -104, -104, -104, -43, -104, -104, -103, -104, -104, -104, + -104 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -83 +static const yytype_int16 yytable[] = +{ + 24, 121, 122, 56, 55, 96, 171, 114, 97, 59, + 60, 179, 35, 180, 38, 39, 48, 8, 42, 43, + 47, 21, 196, 35, 180, 35, 58, 107, 164, 98, + 99, 57, 35, 40, 41, 100, 58, 21, 88, 89, + 90, 93, 147, 149, 151, 152, 177, 154, 91, 156, + 113, 36, 92, 94, 47, 69, 70, 220, 117, 133, + 95, 118, 36, 198, 36, 104, 105, 165, 103, 106, + 127, 36, 174, 124, 111, 128, 129, 130, 132, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 112, 146, 116, 119, 115, 131, 145, 82, 83, 84, + 85, 155, 187, 87, 188, 161, 168, 189, 153, 190, + 172, 157, 169, 170, 227, 173, 158, 159, 160, 170, + 207, 1, 2, 3, 4, 5, 6, 176, 7, 8, + 186, 202, 9, -82, -82, -82, -82, 175, 181, 87, + -82, 211, 101, 46, 212, 213, 214, 221, 102, 185, + 12, 216, 13, 230, 0, 231, 162, 191, 192, 193, + 194, 232, 0, 0, 0, 0, 184, 199, 0, 0, + 170, 0, 0, -45, 0, 0, 16, 203, 17, 0, + 206, 0, 204, 0, 18, 0, 0, 208, 0, 0, + 183, -45, -45, -45, 0, 78, 79, 80, 81, 215, + 82, 83, 84, 85, 0, 0, 87, 0, -48, 0, + 0, 0, 223, 224, 222, 0, 226, 0, 228, 0, + 229, 170, -82, -82, -82, -82, -48, -48, -48, -82, + 0, 101, 0, 0, 0, -45, -45, 102, -45, 210, + 0, -45, 0, 0, 78, 79, 80, 81, 0, 82, + 83, 84, 85, 0, 0, 87, 0, -82, -82, -82, + -82, 0, 0, 0, -82, 0, 101, 0, 0, 0, + -48, -48, 102, -48, 0, 0, -48, 1, 2, 3, + 4, 5, 6, 0, 7, 123, 0, 0, 9, 1, + 2, 3, 4, 5, 6, 0, 7, 44, 0, 0, + 9, 0, 0, 0, 10, 11, 12, 0, 13, 0, + 0, 0, 14, 15, 0, 0, 10, 11, 12, 0, + 13, 0, 0, 0, 14, 15, 0, 0, 0, 0, + 0, 0, 16, 0, 17, 0, 0, -24, 0, -24, + 18, 0, 0, 0, 16, 0, 17, 45, 0, 0, + 0, 0, 18, 1, 2, 3, 4, 5, 6, 0, + 7, 8, 0, 0, 9, 0, 148, 0, 78, 79, + 80, 81, 0, 82, 83, 84, 85, 0, 0, 87, + 10, 11, 12, 0, 13, 0, 0, 0, 14, 15, + 1, 2, 3, 4, 5, 6, 0, 7, 8, 0, + 0, 9, 219, 0, 150, 0, 0, 0, 16, 0, + 17, 0, 0, 0, 0, 0, 18, 10, 11, 12, + 0, 13, 0, 0, 0, 14, 15, 1, 2, 3, + 4, 5, 6, 0, 7, 8, 0, 0, 9, 0, + 0, 0, 0, 0, 0, 16, 0, 17, 0, 0, + 0, 0, 0, 18, 10, 11, 12, 0, 13, 0, + 0, 0, 14, 15, 1, 2, 3, 4, 5, 6, + 0, 7, 44, 0, 0, 9, 0, 0, 0, 0, + 0, 0, 16, 0, 17, 0, 0, 0, 0, 0, + 18, 10, 11, 12, 0, 13, 0, 0, 0, 14, + 15, 1, 2, 3, 4, 5, 6, 0, 7, 205, + 0, 0, 9, 59, 60, 0, 61, 0, 0, 16, + 0, 17, 0, 0, 0, 0, 0, 18, 10, 11, + 12, 0, 13, 59, 60, 0, 14, 15, 0, 0, + 0, 0, 0, 0, 0, 62, 63, 64, 65, 66, + 59, 60, 0, 0, 67, 68, 16, 0, 17, 69, + 70, 0, 0, 0, 18, 62, 63, 64, 65, 66, + 59, 60, 0, 0, 67, 68, 182, 0, 0, 69, + 70, 0, 62, 63, 64, 65, 66, 0, 0, 0, + 0, 67, 68, 209, 0, 0, 69, 70, 0, 0, + 0, 0, 62, 63, 64, 65, 66, 0, 0, 0, + 0, 67, 68, 0, 0, 0, 69, 70, 78, 79, + 80, 81, 0, 82, 83, 84, 85, 0, 0, 87, + 0, 0, 71, 72, 73, 108, 74, 75, 76, 77, + 78, 79, 80, 81, 0, 82, 83, 84, 85, 86, + 0, 87, 225, 109, 110, 71, 72, 73, 178, 74, + 75, 76, 77, 78, 79, 80, 81, 0, 82, 83, + 84, 85, 86, 0, 87, 71, 72, 73, 195, 74, + 75, 76, 77, 78, 79, 80, 81, 0, 82, 83, + 84, 85, 86, 0, 87, 71, 72, 73, 0, 74, + 75, 76, 77, 78, 79, 80, 81, 0, 82, 83, + 84, 85, 86, 108, 87, 0, 0, 0, 78, 79, + 80, 81, 0, 82, 83, 84, 85, 0, 0, 87, + 0, 109, 110, 78, 79, 80, 81, 0, 82, 83, + 84, 85, 0, 0, 87, 0, 200, 201, 78, 79, + 80, 81, 0, 82, 83, 84, 85, 0, 0, 87, + 79, 80, 81, 0, 82, 83, 84, 85, 0, 0, + 87 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 63, 64, 18, 11, 49, 109, 50, 52, 12, + 13, 63, 9, 65, 10, 11, 16, 11, 14, 15, + 16, 0, 63, 9, 65, 9, 62, 63, 9, 50, + 51, 0, 9, 12, 13, 56, 62, 16, 18, 19, + 20, 19, 88, 89, 90, 91, 43, 93, 20, 95, + 50, 48, 20, 19, 50, 58, 59, 43, 58, 74, + 18, 61, 48, 166, 48, 42, 43, 48, 11, 43, + 70, 48, 115, 69, 65, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 63, 87, 67, 58, 65, 74, 25, 34, 35, 36, + 37, 16, 148, 40, 150, 101, 106, 153, 17, 155, + 110, 58, 108, 109, 217, 65, 58, 58, 58, 115, + 182, 3, 4, 5, 6, 7, 8, 3, 10, 11, + 145, 63, 14, 49, 50, 51, 52, 116, 68, 40, + 56, 63, 58, 16, 65, 65, 63, 209, 64, 145, + 32, 58, 34, 63, -1, 63, 101, 157, 158, 159, + 160, 63, -1, -1, -1, -1, 145, 167, -1, -1, + 166, -1, -1, 0, -1, -1, 58, 177, 60, -1, + 180, -1, 178, -1, 66, -1, -1, 183, -1, -1, + 24, 18, 19, 20, -1, 29, 30, 31, 32, 195, + 34, 35, 36, 37, -1, -1, 40, -1, 0, -1, + -1, -1, 212, 213, 210, -1, 216, -1, 218, -1, + 220, 217, 49, 50, 51, 52, 18, 19, 20, 56, + -1, 58, -1, -1, -1, 62, 63, 64, 65, 24, + -1, 68, -1, -1, 29, 30, 31, 32, -1, 34, + 35, 36, 37, -1, -1, 40, -1, 49, 50, 51, + 52, -1, -1, -1, 56, -1, 58, -1, -1, -1, + 62, 63, 64, 65, -1, -1, 68, 3, 4, 5, + 6, 7, 8, -1, 10, 11, -1, -1, 14, 3, + 4, 5, 6, 7, 8, -1, 10, 11, -1, -1, + 14, -1, -1, -1, 30, 31, 32, -1, 34, -1, + -1, -1, 38, 39, -1, -1, 30, 31, 32, -1, + 34, -1, -1, -1, 38, 39, -1, -1, -1, -1, + -1, -1, 58, -1, 60, -1, -1, 63, -1, 65, + 66, -1, -1, -1, 58, -1, 60, 61, -1, -1, + -1, -1, 66, 3, 4, 5, 6, 7, 8, -1, + 10, 11, -1, -1, 14, -1, 16, -1, 29, 30, + 31, 32, -1, 34, 35, 36, 37, -1, -1, 40, + 30, 31, 32, -1, 34, -1, -1, -1, 38, 39, + 3, 4, 5, 6, 7, 8, -1, 10, 11, -1, + -1, 14, 63, -1, 17, -1, -1, -1, 58, -1, + 60, -1, -1, -1, -1, -1, 66, 30, 31, 32, + -1, 34, -1, -1, -1, 38, 39, 3, 4, 5, + 6, 7, 8, -1, 10, 11, -1, -1, 14, -1, + -1, -1, -1, -1, -1, 58, -1, 60, -1, -1, + -1, -1, -1, 66, 30, 31, 32, -1, 34, -1, + -1, -1, 38, 39, 3, 4, 5, 6, 7, 8, + -1, 10, 11, -1, -1, 14, -1, -1, -1, -1, + -1, -1, 58, -1, 60, -1, -1, -1, -1, -1, + 66, 30, 31, 32, -1, 34, -1, -1, -1, 38, + 39, 3, 4, 5, 6, 7, 8, -1, 10, 11, + -1, -1, 14, 12, 13, -1, 15, -1, -1, 58, + -1, 60, -1, -1, -1, -1, -1, 66, 30, 31, + 32, -1, 34, 12, 13, -1, 38, 39, -1, -1, + -1, -1, -1, -1, -1, 44, 45, 46, 47, 48, + 12, 13, -1, -1, 53, 54, 58, -1, 60, 58, + 59, -1, -1, -1, 66, 44, 45, 46, 47, 48, + 12, 13, -1, -1, 53, 54, 55, -1, -1, 58, + 59, -1, 44, 45, 46, 47, 48, -1, -1, -1, + -1, 53, 54, 55, -1, -1, 58, 59, -1, -1, + -1, -1, 44, 45, 46, 47, 48, -1, -1, -1, + -1, 53, 54, -1, -1, -1, 58, 59, 29, 30, + 31, 32, -1, 34, 35, 36, 37, -1, -1, 40, + -1, -1, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, -1, 34, 35, 36, 37, 38, + -1, 40, 63, 42, 43, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, 34, 35, + 36, 37, 38, -1, 40, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, 34, 35, + 36, 37, 38, -1, 40, 21, 22, 23, -1, 25, + 26, 27, 28, 29, 30, 31, 32, -1, 34, 35, + 36, 37, 38, 24, 40, -1, -1, -1, 29, 30, + 31, 32, -1, 34, 35, 36, 37, -1, -1, 40, + -1, 42, 43, 29, 30, 31, 32, -1, 34, 35, + 36, 37, -1, -1, 40, -1, 42, 43, 29, 30, + 31, 32, -1, 34, 35, 36, 37, -1, -1, 40, + 30, 31, 32, -1, 34, 35, 36, 37, -1, -1, + 40 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 10, 11, 14, + 30, 31, 32, 34, 38, 39, 58, 60, 66, 70, + 71, 72, 75, 77, 78, 79, 80, 81, 82, 83, + 85, 86, 87, 88, 89, 9, 48, 72, 75, 75, + 72, 72, 75, 75, 11, 61, 71, 75, 78, 90, + 91, 92, 93, 94, 95, 11, 87, 0, 62, 12, + 13, 15, 44, 45, 46, 47, 48, 53, 54, 58, + 59, 21, 22, 23, 25, 26, 27, 28, 29, 30, + 31, 32, 34, 35, 36, 37, 38, 40, 18, 19, + 20, 20, 20, 19, 19, 18, 49, 52, 50, 51, + 56, 58, 64, 11, 42, 43, 43, 63, 24, 42, + 43, 65, 63, 78, 92, 65, 67, 78, 78, 58, + 84, 84, 84, 11, 75, 76, 78, 78, 75, 75, + 75, 72, 75, 87, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 25, 75, 77, 16, 77, + 17, 77, 77, 17, 77, 16, 77, 58, 58, 58, + 58, 75, 76, 74, 9, 48, 98, 96, 78, 75, + 75, 95, 78, 65, 92, 72, 3, 43, 24, 63, + 65, 68, 55, 24, 72, 75, 87, 77, 77, 77, + 77, 78, 78, 78, 78, 24, 63, 73, 95, 78, + 42, 43, 63, 78, 75, 11, 78, 84, 75, 55, + 24, 63, 65, 65, 63, 75, 58, 99, 97, 63, + 43, 84, 75, 78, 78, 63, 78, 95, 78, 78, + 63, 63, 63 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to xreallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to xreallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: + +/* Line 1455 of yacc.c */ +#line 239 "ada-exp.y" + { write_exp_elt_opcode (BINOP_COMMA); } + break; + + case 5: + +/* Line 1455 of yacc.c */ +#line 241 "ada-exp.y" + { write_exp_elt_opcode (BINOP_ASSIGN); } + break; + + case 6: + +/* Line 1455 of yacc.c */ +#line 246 "ada-exp.y" + { write_exp_elt_opcode (UNOP_IND); } + break; + + case 7: + +/* Line 1455 of yacc.c */ +#line 250 "ada-exp.y" + { write_exp_op_with_string (STRUCTOP_STRUCT, (yyvsp[(2) - (2)].sval)); } + break; + + case 8: + +/* Line 1455 of yacc.c */ +#line 254 "ada-exp.y" + { + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((yyvsp[(3) - (4)].lval)); + write_exp_elt_opcode (OP_FUNCALL); + } + break; + + case 9: + +/* Line 1455 of yacc.c */ +#line 260 "ada-exp.y" + { + if ((yyvsp[(1) - (4)].tval) != NULL) + { + if ((yyvsp[(3) - (4)].lval) != 1) + error (_("Invalid conversion")); + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ((yyvsp[(1) - (4)].tval)); + write_exp_elt_opcode (UNOP_CAST); + } + else + { + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((yyvsp[(3) - (4)].lval)); + write_exp_elt_opcode (OP_FUNCALL); + } + } + break; + + case 10: + +/* Line 1455 of yacc.c */ +#line 278 "ada-exp.y" + { type_qualifier = (yyvsp[(1) - (3)].tval); } + break; + + case 11: + +/* Line 1455 of yacc.c */ +#line 280 "ada-exp.y" + { + if ((yyvsp[(1) - (7)].tval) == NULL) + error (_("Type required for qualification")); + write_exp_elt_opcode (UNOP_QUAL); + write_exp_elt_type ((yyvsp[(1) - (7)].tval)); + write_exp_elt_opcode (UNOP_QUAL); + type_qualifier = (yyvsp[(3) - (7)].tval); + } + break; + + case 12: + +/* Line 1455 of yacc.c */ +#line 290 "ada-exp.y" + { (yyval.tval) = type_qualifier; } + break; + + case 13: + +/* Line 1455 of yacc.c */ +#line 295 "ada-exp.y" + { write_exp_elt_opcode (TERNOP_SLICE); } + break; + + case 14: + +/* Line 1455 of yacc.c */ +#line 297 "ada-exp.y" + { if ((yyvsp[(1) - (6)].tval) == NULL) + write_exp_elt_opcode (TERNOP_SLICE); + else + error (_("Cannot slice a type")); + } + break; + + case 15: + +/* Line 1455 of yacc.c */ +#line 304 "ada-exp.y" + { } + break; + + case 16: + +/* Line 1455 of yacc.c */ +#line 316 "ada-exp.y" + { if ((yyvsp[(1) - (1)].tval) != NULL) + { + write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type ((yyvsp[(1) - (1)].tval)); + write_exp_elt_opcode (OP_TYPE); + } + } + break; + + case 17: + +/* Line 1455 of yacc.c */ +#line 326 "ada-exp.y" + { write_dollar_variable ((yyvsp[(1) - (1)].sval)); } + break; + + case 20: + +/* Line 1455 of yacc.c */ +#line 336 "ada-exp.y" + { write_exp_elt_opcode (UNOP_NEG); } + break; + + case 21: + +/* Line 1455 of yacc.c */ +#line 340 "ada-exp.y" + { write_exp_elt_opcode (UNOP_PLUS); } + break; + + case 22: + +/* Line 1455 of yacc.c */ +#line 344 "ada-exp.y" + { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } + break; + + case 23: + +/* Line 1455 of yacc.c */ +#line 348 "ada-exp.y" + { write_exp_elt_opcode (UNOP_ABS); } + break; + + case 24: + +/* Line 1455 of yacc.c */ +#line 351 "ada-exp.y" + { (yyval.lval) = 0; } + break; + + case 25: + +/* Line 1455 of yacc.c */ +#line 355 "ada-exp.y" + { (yyval.lval) = 1; } + break; + + case 26: + +/* Line 1455 of yacc.c */ +#line 357 "ada-exp.y" + { (yyval.lval) = 1; } + break; + + case 27: + +/* Line 1455 of yacc.c */ +#line 359 "ada-exp.y" + { (yyval.lval) = (yyvsp[(1) - (3)].lval) + 1; } + break; + + case 28: + +/* Line 1455 of yacc.c */ +#line 361 "ada-exp.y" + { (yyval.lval) = (yyvsp[(1) - (5)].lval) + 1; } + break; + + case 29: + +/* Line 1455 of yacc.c */ +#line 366 "ada-exp.y" + { + if ((yyvsp[(2) - (4)].tval) == NULL) + error (_("Type required within braces in coercion")); + write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type ((yyvsp[(2) - (4)].tval)); + write_exp_elt_opcode (UNOP_MEMVAL); + } + break; + + case 30: + +/* Line 1455 of yacc.c */ +#line 378 "ada-exp.y" + { write_exp_elt_opcode (BINOP_EXP); } + break; + + case 31: + +/* Line 1455 of yacc.c */ +#line 382 "ada-exp.y" + { write_exp_elt_opcode (BINOP_MUL); } + break; + + case 32: + +/* Line 1455 of yacc.c */ +#line 386 "ada-exp.y" + { write_exp_elt_opcode (BINOP_DIV); } + break; + + case 33: + +/* Line 1455 of yacc.c */ +#line 390 "ada-exp.y" + { write_exp_elt_opcode (BINOP_REM); } + break; + + case 34: + +/* Line 1455 of yacc.c */ +#line 394 "ada-exp.y" + { write_exp_elt_opcode (BINOP_MOD); } + break; + + case 35: + +/* Line 1455 of yacc.c */ +#line 398 "ada-exp.y" + { write_exp_elt_opcode (BINOP_REPEAT); } + break; + + case 36: + +/* Line 1455 of yacc.c */ +#line 402 "ada-exp.y" + { write_exp_elt_opcode (BINOP_ADD); } + break; + + case 37: + +/* Line 1455 of yacc.c */ +#line 406 "ada-exp.y" + { write_exp_elt_opcode (BINOP_CONCAT); } + break; + + case 38: + +/* Line 1455 of yacc.c */ +#line 410 "ada-exp.y" + { write_exp_elt_opcode (BINOP_SUB); } + break; + + case 40: + +/* Line 1455 of yacc.c */ +#line 417 "ada-exp.y" + { write_exp_elt_opcode (BINOP_EQUAL); } + break; + + case 41: + +/* Line 1455 of yacc.c */ +#line 421 "ada-exp.y" + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + break; + + case 42: + +/* Line 1455 of yacc.c */ +#line 425 "ada-exp.y" + { write_exp_elt_opcode (BINOP_LEQ); } + break; + + case 43: + +/* Line 1455 of yacc.c */ +#line 429 "ada-exp.y" + { write_exp_elt_opcode (TERNOP_IN_RANGE); } + break; + + case 44: + +/* Line 1455 of yacc.c */ +#line 431 "ada-exp.y" + { write_exp_elt_opcode (BINOP_IN_BOUNDS); + write_exp_elt_longcst ((LONGEST) (yyvsp[(5) - (5)].lval)); + write_exp_elt_opcode (BINOP_IN_BOUNDS); + } + break; + + case 45: + +/* Line 1455 of yacc.c */ +#line 436 "ada-exp.y" + { + if ((yyvsp[(3) - (3)].tval) == NULL) + error (_("Right operand of 'in' must be type")); + write_exp_elt_opcode (UNOP_IN_RANGE); + write_exp_elt_type ((yyvsp[(3) - (3)].tval)); + write_exp_elt_opcode (UNOP_IN_RANGE); + } + break; + + case 46: + +/* Line 1455 of yacc.c */ +#line 444 "ada-exp.y" + { write_exp_elt_opcode (TERNOP_IN_RANGE); + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + break; + + case 47: + +/* Line 1455 of yacc.c */ +#line 448 "ada-exp.y" + { write_exp_elt_opcode (BINOP_IN_BOUNDS); + write_exp_elt_longcst ((LONGEST) (yyvsp[(6) - (6)].lval)); + write_exp_elt_opcode (BINOP_IN_BOUNDS); + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + break; + + case 48: + +/* Line 1455 of yacc.c */ +#line 454 "ada-exp.y" + { + if ((yyvsp[(4) - (4)].tval) == NULL) + error (_("Right operand of 'in' must be type")); + write_exp_elt_opcode (UNOP_IN_RANGE); + write_exp_elt_type ((yyvsp[(4) - (4)].tval)); + write_exp_elt_opcode (UNOP_IN_RANGE); + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + break; + + case 49: + +/* Line 1455 of yacc.c */ +#line 465 "ada-exp.y" + { write_exp_elt_opcode (BINOP_GEQ); } + break; + + case 50: + +/* Line 1455 of yacc.c */ +#line 469 "ada-exp.y" + { write_exp_elt_opcode (BINOP_LESS); } + break; + + case 51: + +/* Line 1455 of yacc.c */ +#line 473 "ada-exp.y" + { write_exp_elt_opcode (BINOP_GTR); } + break; + + case 58: + +/* Line 1455 of yacc.c */ +#line 486 "ada-exp.y" + { write_exp_elt_opcode (BINOP_BITWISE_AND); } + break; + + case 59: + +/* Line 1455 of yacc.c */ +#line 488 "ada-exp.y" + { write_exp_elt_opcode (BINOP_BITWISE_AND); } + break; + + case 60: + +/* Line 1455 of yacc.c */ +#line 493 "ada-exp.y" + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + break; + + case 61: + +/* Line 1455 of yacc.c */ +#line 495 "ada-exp.y" + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + break; + + case 62: + +/* Line 1455 of yacc.c */ +#line 500 "ada-exp.y" + { write_exp_elt_opcode (BINOP_BITWISE_IOR); } + break; + + case 63: + +/* Line 1455 of yacc.c */ +#line 502 "ada-exp.y" + { write_exp_elt_opcode (BINOP_BITWISE_IOR); } + break; + + case 64: + +/* Line 1455 of yacc.c */ +#line 507 "ada-exp.y" + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + break; + + case 65: + +/* Line 1455 of yacc.c */ +#line 509 "ada-exp.y" + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + break; + + case 66: + +/* Line 1455 of yacc.c */ +#line 513 "ada-exp.y" + { write_exp_elt_opcode (BINOP_BITWISE_XOR); } + break; + + case 67: + +/* Line 1455 of yacc.c */ +#line 515 "ada-exp.y" + { write_exp_elt_opcode (BINOP_BITWISE_XOR); } + break; + + case 68: + +/* Line 1455 of yacc.c */ +#line 527 "ada-exp.y" + { write_exp_elt_opcode (UNOP_ADDR); } + break; + + case 69: + +/* Line 1455 of yacc.c */ +#line 529 "ada-exp.y" + { write_exp_elt_opcode (UNOP_ADDR); + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (type_system_address ()); + write_exp_elt_opcode (UNOP_CAST); + } + break; + + case 70: + +/* Line 1455 of yacc.c */ +#line 535 "ada-exp.y" + { write_int ((yyvsp[(3) - (3)].lval), type_int ()); + write_exp_elt_opcode (OP_ATR_FIRST); } + break; + + case 71: + +/* Line 1455 of yacc.c */ +#line 538 "ada-exp.y" + { write_int ((yyvsp[(3) - (3)].lval), type_int ()); + write_exp_elt_opcode (OP_ATR_LAST); } + break; + + case 72: + +/* Line 1455 of yacc.c */ +#line 541 "ada-exp.y" + { write_int ((yyvsp[(3) - (3)].lval), type_int ()); + write_exp_elt_opcode (OP_ATR_LENGTH); } + break; + + case 73: + +/* Line 1455 of yacc.c */ +#line 544 "ada-exp.y" + { write_exp_elt_opcode (OP_ATR_SIZE); } + break; + + case 74: + +/* Line 1455 of yacc.c */ +#line 546 "ada-exp.y" + { write_exp_elt_opcode (OP_ATR_TAG); } + break; + + case 75: + +/* Line 1455 of yacc.c */ +#line 548 "ada-exp.y" + { write_exp_elt_opcode (OP_ATR_MIN); } + break; + + case 76: + +/* Line 1455 of yacc.c */ +#line 550 "ada-exp.y" + { write_exp_elt_opcode (OP_ATR_MAX); } + break; + + case 77: + +/* Line 1455 of yacc.c */ +#line 552 "ada-exp.y" + { write_exp_elt_opcode (OP_ATR_POS); } + break; + + case 78: + +/* Line 1455 of yacc.c */ +#line 554 "ada-exp.y" + { write_exp_elt_opcode (OP_ATR_VAL); } + break; + + case 79: + +/* Line 1455 of yacc.c */ +#line 556 "ada-exp.y" + { write_exp_elt_opcode (OP_ATR_MODULUS); } + break; + + case 80: + +/* Line 1455 of yacc.c */ +#line 560 "ada-exp.y" + { (yyval.lval) = 1; } + break; + + case 81: + +/* Line 1455 of yacc.c */ +#line 562 "ada-exp.y" + { (yyval.lval) = (yyvsp[(2) - (3)].typed_val).val; } + break; + + case 82: + +/* Line 1455 of yacc.c */ +#line 567 "ada-exp.y" + { + if ((yyvsp[(1) - (1)].tval) == NULL) + error (_("Prefix must be type")); + write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type ((yyvsp[(1) - (1)].tval)); + write_exp_elt_opcode (OP_TYPE); } + break; + + case 84: + +/* Line 1455 of yacc.c */ +#line 578 "ada-exp.y" + { write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type (parse_type->builtin_void); + write_exp_elt_opcode (OP_TYPE); } + break; + + case 85: + +/* Line 1455 of yacc.c */ +#line 585 "ada-exp.y" + { write_int ((LONGEST) (yyvsp[(1) - (1)].typed_val).val, (yyvsp[(1) - (1)].typed_val).type); } + break; + + case 86: + +/* Line 1455 of yacc.c */ +#line 589 "ada-exp.y" + { write_int (convert_char_literal (type_qualifier, (yyvsp[(1) - (1)].typed_val).val), + (type_qualifier == NULL) + ? (yyvsp[(1) - (1)].typed_val).type : type_qualifier); + } + break; + + case 87: + +/* Line 1455 of yacc.c */ +#line 596 "ada-exp.y" + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type ((yyvsp[(1) - (1)].typed_val_float).type); + write_exp_elt_dblcst ((yyvsp[(1) - (1)].typed_val_float).dval); + write_exp_elt_opcode (OP_DOUBLE); + } + break; + + case 88: + +/* Line 1455 of yacc.c */ +#line 604 "ada-exp.y" + { write_int (0, type_int ()); } + break; + + case 89: + +/* Line 1455 of yacc.c */ +#line 608 "ada-exp.y" + { + write_exp_op_with_string (OP_STRING, (yyvsp[(1) - (1)].sval)); + } + break; + + case 90: + +/* Line 1455 of yacc.c */ +#line 614 "ada-exp.y" + { write_int (1, type_boolean ()); } + break; + + case 91: + +/* Line 1455 of yacc.c */ +#line 616 "ada-exp.y" + { write_int (0, type_boolean ()); } + break; + + case 92: + +/* Line 1455 of yacc.c */ +#line 620 "ada-exp.y" + { error (_("NEW not implemented.")); } + break; + + case 93: + +/* Line 1455 of yacc.c */ +#line 624 "ada-exp.y" + { (yyval.tval) = write_var_or_type (NULL, (yyvsp[(1) - (1)].sval)); } + break; + + case 94: + +/* Line 1455 of yacc.c */ +#line 626 "ada-exp.y" + { (yyval.tval) = write_var_or_type ((yyvsp[(1) - (2)].bval), (yyvsp[(2) - (2)].sval)); } + break; + + case 95: + +/* Line 1455 of yacc.c */ +#line 628 "ada-exp.y" + { + (yyval.tval) = write_var_or_type (NULL, (yyvsp[(1) - (2)].sval)); + if ((yyval.tval) == NULL) + write_exp_elt_opcode (UNOP_ADDR); + else + (yyval.tval) = lookup_pointer_type ((yyval.tval)); + } + break; + + case 96: + +/* Line 1455 of yacc.c */ +#line 636 "ada-exp.y" + { + (yyval.tval) = write_var_or_type ((yyvsp[(1) - (3)].bval), (yyvsp[(2) - (3)].sval)); + if ((yyval.tval) == NULL) + write_exp_elt_opcode (UNOP_ADDR); + else + (yyval.tval) = lookup_pointer_type ((yyval.tval)); + } + break; + + case 97: + +/* Line 1455 of yacc.c */ +#line 647 "ada-exp.y" + { (yyval.bval) = block_lookup (NULL, (yyvsp[(1) - (2)].sval).ptr); } + break; + + case 98: + +/* Line 1455 of yacc.c */ +#line 649 "ada-exp.y" + { (yyval.bval) = block_lookup ((yyvsp[(1) - (3)].bval), (yyvsp[(2) - (3)].sval).ptr); } + break; + + case 99: + +/* Line 1455 of yacc.c */ +#line 654 "ada-exp.y" + { + write_exp_elt_opcode (OP_AGGREGATE); + write_exp_elt_longcst ((yyvsp[(2) - (3)].lval)); + write_exp_elt_opcode (OP_AGGREGATE); + } + break; + + case 100: + +/* Line 1455 of yacc.c */ +#line 662 "ada-exp.y" + { (yyval.lval) = (yyvsp[(1) - (1)].lval); } + break; + + case 101: + +/* Line 1455 of yacc.c */ +#line 664 "ada-exp.y" + { write_exp_elt_opcode (OP_POSITIONAL); + write_exp_elt_longcst ((yyvsp[(1) - (2)].lval)); + write_exp_elt_opcode (OP_POSITIONAL); + (yyval.lval) = (yyvsp[(1) - (2)].lval) + 1; + } + break; + + case 102: + +/* Line 1455 of yacc.c */ +#line 670 "ada-exp.y" + { (yyval.lval) = (yyvsp[(1) - (2)].lval) + (yyvsp[(2) - (2)].lval); } + break; + + case 103: + +/* Line 1455 of yacc.c */ +#line 675 "ada-exp.y" + { write_exp_elt_opcode (OP_POSITIONAL); + write_exp_elt_longcst (0); + write_exp_elt_opcode (OP_POSITIONAL); + (yyval.lval) = 1; + } + break; + + case 104: + +/* Line 1455 of yacc.c */ +#line 681 "ada-exp.y" + { write_exp_elt_opcode (OP_POSITIONAL); + write_exp_elt_longcst ((yyvsp[(1) - (3)].lval)); + write_exp_elt_opcode (OP_POSITIONAL); + (yyval.lval) = (yyvsp[(1) - (3)].lval) + 1; + } + break; + + case 105: + +/* Line 1455 of yacc.c */ +#line 689 "ada-exp.y" + { (yyval.lval) = 1; } + break; + + case 106: + +/* Line 1455 of yacc.c */ +#line 690 "ada-exp.y" + { (yyval.lval) = 1; } + break; + + case 107: + +/* Line 1455 of yacc.c */ +#line 692 "ada-exp.y" + { (yyval.lval) = (yyvsp[(3) - (3)].lval) + 1; } + break; + + case 108: + +/* Line 1455 of yacc.c */ +#line 696 "ada-exp.y" + { write_exp_elt_opcode (OP_OTHERS); } + break; + + case 109: + +/* Line 1455 of yacc.c */ +#line 701 "ada-exp.y" + { + write_exp_elt_opcode (OP_CHOICES); + write_exp_elt_longcst ((yyvsp[(1) - (1)].lval)); + write_exp_elt_opcode (OP_CHOICES); + } + break; + + case 110: + +/* Line 1455 of yacc.c */ +#line 715 "ada-exp.y" + { write_name_assoc ((yyvsp[(1) - (2)].sval)); } + break; + + case 111: + +/* Line 1455 of yacc.c */ +#line 716 "ada-exp.y" + { (yyval.lval) = 1; } + break; + + case 112: + +/* Line 1455 of yacc.c */ +#line 718 "ada-exp.y" + { (yyval.lval) = 1; } + break; + + case 113: + +/* Line 1455 of yacc.c */ +#line 720 "ada-exp.y" + { write_exp_elt_opcode (OP_DISCRETE_RANGE); + write_exp_op_with_string (OP_NAME, empty_stoken); + } + break; + + case 114: + +/* Line 1455 of yacc.c */ +#line 723 "ada-exp.y" + { (yyval.lval) = 1; } + break; + + case 115: + +/* Line 1455 of yacc.c */ +#line 725 "ada-exp.y" + { write_name_assoc ((yyvsp[(1) - (2)].sval)); } + break; + + case 116: + +/* Line 1455 of yacc.c */ +#line 726 "ada-exp.y" + { (yyval.lval) = (yyvsp[(4) - (4)].lval) + 1; } + break; + + case 117: + +/* Line 1455 of yacc.c */ +#line 728 "ada-exp.y" + { (yyval.lval) = (yyvsp[(3) - (3)].lval) + 1; } + break; + + case 118: + +/* Line 1455 of yacc.c */ +#line 730 "ada-exp.y" + { write_exp_elt_opcode (OP_DISCRETE_RANGE); } + break; + + case 119: + +/* Line 1455 of yacc.c */ +#line 731 "ada-exp.y" + { (yyval.lval) = (yyvsp[(6) - (6)].lval) + 1; } + break; + + case 120: + +/* Line 1455 of yacc.c */ +#line 738 "ada-exp.y" + { write_exp_elt_opcode (UNOP_IND); } + break; + + case 121: + +/* Line 1455 of yacc.c */ +#line 740 "ada-exp.y" + { write_exp_elt_opcode (UNOP_ADDR); } + break; + + case 122: + +/* Line 1455 of yacc.c */ +#line 742 "ada-exp.y" + { write_exp_elt_opcode (BINOP_SUBSCRIPT); } + break; + + + +/* Line 1455 of yacc.c */ +#line 2773 "ada-exp.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1675 of yacc.c */ +#line 745 "ada-exp.y" + + +/* yylex defined in ada-lex.c: Reads one token, getting characters */ +/* through lexptr. */ + +/* Remap normal flex interface names (yylex) as well as gratuitiously */ +/* global symbol names, so we can have multiple flex-generated parsers */ +/* in gdb. */ + +/* (See note above on previous definitions for YACC.) */ + +#define yy_create_buffer ada_yy_create_buffer +#define yy_delete_buffer ada_yy_delete_buffer +#define yy_init_buffer ada_yy_init_buffer +#define yy_load_buffer_state ada_yy_load_buffer_state +#define yy_switch_to_buffer ada_yy_switch_to_buffer +#define yyrestart ada_yyrestart +#define yytext ada_yytext +#define yywrap ada_yywrap + +static struct obstack temp_parse_space; + +/* The following kludge was found necessary to prevent conflicts between */ +/* defs.h and non-standard stdlib.h files. */ +#define qsort __qsort__dummy +#include "ada-lex.c" + +int +ada_parse (void) +{ + lexer_init (yyin); /* (Re-)initialize lexer. */ + type_qualifier = NULL; + obstack_free (&temp_parse_space, NULL); + obstack_init (&temp_parse_space); + + return _ada_parse (); +} + +void +yyerror (char *msg) +{ + error (_("Error in expression, near `%s'."), lexptr); +} + +/* The operator name corresponding to operator symbol STRING (adds + quotes and maps to lower-case). Destroys the previous contents of + the array pointed to by STRING.ptr. Error if STRING does not match + a valid Ada operator. Assumes that STRING.ptr points to a + null-terminated string and that, if STRING is a valid operator + symbol, the array pointed to by STRING.ptr contains at least + STRING.length+3 characters. */ + +static struct stoken +string_to_operator (struct stoken string) +{ + int i; + + for (i = 0; ada_opname_table[i].encoded != NULL; i += 1) + { + if (string.length == strlen (ada_opname_table[i].decoded)-2 + && strncasecmp (string.ptr, ada_opname_table[i].decoded+1, + string.length) == 0) + { + strncpy (string.ptr, ada_opname_table[i].decoded, + string.length+2); + string.length += 2; + return string; + } + } + error (_("Invalid operator symbol `%s'"), string.ptr); +} + +/* Emit expression to access an instance of SYM, in block BLOCK (if + * non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */ +static void +write_var_from_sym (const struct block *orig_left_context, + const struct block *block, + struct symbol *sym) +{ + if (orig_left_context == NULL && symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 + || contained_in (block, innermost_block)) + innermost_block = block; + } + + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (block); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); +} + +/* Write integer or boolean constant ARG of type TYPE. */ + +static void +write_int (LONGEST arg, struct type *type) +{ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (type); + write_exp_elt_longcst (arg); + write_exp_elt_opcode (OP_LONG); +} + +/* Write an OPCODE, string, OPCODE sequence to the current expression. */ +static void +write_exp_op_with_string (enum exp_opcode opcode, struct stoken token) +{ + write_exp_elt_opcode (opcode); + write_exp_string (token); + write_exp_elt_opcode (opcode); +} + +/* Emit expression corresponding to the renamed object named + * designated by RENAMED_ENTITY[0 .. RENAMED_ENTITY_LEN-1] in the + * context of ORIG_LEFT_CONTEXT, to which is applied the operations + * encoded by RENAMING_EXPR. MAX_DEPTH is the maximum number of + * cascaded renamings to allow. If ORIG_LEFT_CONTEXT is null, it + * defaults to the currently selected block. ORIG_SYMBOL is the + * symbol that originally encoded the renaming. It is needed only + * because its prefix also qualifies any index variables used to index + * or slice an array. It should not be necessary once we go to the + * new encoding entirely (FIXME pnh 7/20/2007). */ + +static void +write_object_renaming (const struct block *orig_left_context, + const char *renamed_entity, int renamed_entity_len, + const char *renaming_expr, int max_depth) +{ + char *name; + enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state; + struct ada_symbol_info sym_info; + + if (max_depth <= 0) + error (_("Could not find renamed symbol")); + + if (orig_left_context == NULL) + orig_left_context = get_selected_block (NULL); + + name = obstack_copy0 (&temp_parse_space, renamed_entity, renamed_entity_len); + ada_lookup_encoded_symbol (name, orig_left_context, VAR_DOMAIN, &sym_info); + if (sym_info.sym == NULL) + error (_("Could not find renamed variable: %s"), ada_decode (name)); + else if (SYMBOL_CLASS (sym_info.sym) == LOC_TYPEDEF) + /* We have a renaming of an old-style renaming symbol. Don't + trust the block information. */ + sym_info.block = orig_left_context; + + { + const char *inner_renamed_entity; + int inner_renamed_entity_len; + const char *inner_renaming_expr; + + switch (ada_parse_renaming (sym_info.sym, &inner_renamed_entity, + &inner_renamed_entity_len, + &inner_renaming_expr)) + { + case ADA_NOT_RENAMING: + write_var_from_sym (orig_left_context, sym_info.block, sym_info.sym); + break; + case ADA_OBJECT_RENAMING: + write_object_renaming (sym_info.block, + inner_renamed_entity, inner_renamed_entity_len, + inner_renaming_expr, max_depth - 1); + break; + default: + goto BadEncoding; + } + } + + slice_state = SIMPLE_INDEX; + while (*renaming_expr == 'X') + { + renaming_expr += 1; + + switch (*renaming_expr) { + case 'A': + renaming_expr += 1; + write_exp_elt_opcode (UNOP_IND); + break; + case 'L': + slice_state = LOWER_BOUND; + /* FALLTHROUGH */ + case 'S': + renaming_expr += 1; + if (isdigit (*renaming_expr)) + { + char *next; + long val = strtol (renaming_expr, &next, 10); + if (next == renaming_expr) + goto BadEncoding; + renaming_expr = next; + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (type_int ()); + write_exp_elt_longcst ((LONGEST) val); + write_exp_elt_opcode (OP_LONG); + } + else + { + const char *end; + char *index_name; + struct ada_symbol_info index_sym_info; + + end = strchr (renaming_expr, 'X'); + if (end == NULL) + end = renaming_expr + strlen (renaming_expr); + + index_name = + obstack_copy0 (&temp_parse_space, renaming_expr, + end - renaming_expr); + renaming_expr = end; + + ada_lookup_encoded_symbol (index_name, NULL, VAR_DOMAIN, + &index_sym_info); + if (index_sym_info.sym == NULL) + error (_("Could not find %s"), index_name); + else if (SYMBOL_CLASS (index_sym_info.sym) == LOC_TYPEDEF) + /* Index is an old-style renaming symbol. */ + index_sym_info.block = orig_left_context; + write_var_from_sym (NULL, index_sym_info.block, + index_sym_info.sym); + } + if (slice_state == SIMPLE_INDEX) + { + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) 1); + write_exp_elt_opcode (OP_FUNCALL); + } + else if (slice_state == LOWER_BOUND) + slice_state = UPPER_BOUND; + else if (slice_state == UPPER_BOUND) + { + write_exp_elt_opcode (TERNOP_SLICE); + slice_state = SIMPLE_INDEX; + } + break; + + case 'R': + { + struct stoken field_name; + const char *end; + renaming_expr += 1; + + if (slice_state != SIMPLE_INDEX) + goto BadEncoding; + end = strchr (renaming_expr, 'X'); + if (end == NULL) + end = renaming_expr + strlen (renaming_expr); + field_name.length = end - renaming_expr; + field_name.ptr = xmalloc (end - renaming_expr + 1); + strncpy (field_name.ptr, renaming_expr, end - renaming_expr); + field_name.ptr[end - renaming_expr] = '\000'; + renaming_expr = end; + write_exp_op_with_string (STRUCTOP_STRUCT, field_name); + break; + } + + default: + goto BadEncoding; + } + } + if (slice_state == SIMPLE_INDEX) + return; + + BadEncoding: + error (_("Internal error in encoding of renaming declaration")); +} + +static struct block* +block_lookup (struct block *context, char *raw_name) +{ + char *name; + struct ada_symbol_info *syms; + int nsyms; + struct symtab *symtab; + + if (raw_name[0] == '\'') + { + raw_name += 1; + name = raw_name; + } + else + name = ada_encode (raw_name); + + nsyms = ada_lookup_symbol_list (name, context, VAR_DOMAIN, &syms); + if (context == NULL + && (nsyms == 0 || SYMBOL_CLASS (syms[0].sym) != LOC_BLOCK)) + symtab = lookup_symtab (name); + else + symtab = NULL; + + if (symtab != NULL) + return BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK); + else if (nsyms == 0 || SYMBOL_CLASS (syms[0].sym) != LOC_BLOCK) + { + if (context == NULL) + error (_("No file or function \"%s\"."), raw_name); + else + error (_("No function \"%s\" in specified context."), raw_name); + } + else + { + if (nsyms > 1) + warning (_("Function name \"%s\" ambiguous here"), raw_name); + return SYMBOL_BLOCK_VALUE (syms[0].sym); + } +} + +static struct symbol* +select_possible_type_sym (struct ada_symbol_info *syms, int nsyms) +{ + int i; + int preferred_index; + struct type *preferred_type; + + preferred_index = -1; preferred_type = NULL; + for (i = 0; i < nsyms; i += 1) + switch (SYMBOL_CLASS (syms[i].sym)) + { + case LOC_TYPEDEF: + if (ada_prefer_type (SYMBOL_TYPE (syms[i].sym), preferred_type)) + { + preferred_index = i; + preferred_type = SYMBOL_TYPE (syms[i].sym); + } + break; + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_COMPUTED: + return NULL; + default: + break; + } + if (preferred_type == NULL) + return NULL; + return syms[preferred_index].sym; +} + +static struct type* +find_primitive_type (char *name) +{ + struct type *type; + type = language_lookup_primitive_type_by_name (parse_language, + parse_gdbarch, + name); + if (type == NULL && strcmp ("system__address", name) == 0) + type = type_system_address (); + + if (type != NULL) + { + /* Check to see if we have a regular definition of this + type that just didn't happen to have been read yet. */ + struct symbol *sym; + char *expanded_name = + (char *) alloca (strlen (name) + sizeof ("standard__")); + strcpy (expanded_name, "standard__"); + strcat (expanded_name, name); + sym = ada_lookup_symbol (expanded_name, NULL, VAR_DOMAIN, NULL); + if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + type = SYMBOL_TYPE (sym); + } + + return type; +} + +static int +chop_selector (char *name, int end) +{ + int i; + for (i = end - 1; i > 0; i -= 1) + if (name[i] == '.' || (name[i] == '_' && name[i+1] == '_')) + return i; + return -1; +} + +/* If NAME is a string beginning with a separator (either '__', or + '.'), chop this separator and return the result; else, return + NAME. */ + +static char * +chop_separator (char *name) +{ + if (*name == '.') + return name + 1; + + if (name[0] == '_' && name[1] == '_') + return name + 2; + + return name; +} + +/* Given that SELS is a string of the form ()*, where + is '__' or '.', write the indicated sequence of + STRUCTOP_STRUCT expression operators. */ +static void +write_selectors (char *sels) +{ + while (*sels != '\0') + { + struct stoken field_name; + char *p = chop_separator (sels); + sels = p; + while (*sels != '\0' && *sels != '.' + && (sels[0] != '_' || sels[1] != '_')) + sels += 1; + field_name.length = sels - p; + field_name.ptr = p; + write_exp_op_with_string (STRUCTOP_STRUCT, field_name); + } +} + +/* Write a variable access (OP_VAR_VALUE) to ambiguous encoded name + NAME[0..LEN-1], in block context BLOCK, to be resolved later. Writes + a temporary symbol that is valid until the next call to ada_parse. + */ +static void +write_ambiguous_var (const struct block *block, char *name, int len) +{ + struct symbol *sym = + obstack_alloc (&temp_parse_space, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_DOMAIN (sym) = UNDEF_DOMAIN; + SYMBOL_LINKAGE_NAME (sym) = obstack_copy0 (&temp_parse_space, name, len); + SYMBOL_LANGUAGE (sym) = language_ada; + + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (block); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); +} + +/* A convenient wrapper around ada_get_field_index that takes + a non NUL-terminated FIELD_NAME0 and a FIELD_NAME_LEN instead + of a NUL-terminated field name. */ + +static int +ada_nget_field_index (const struct type *type, const char *field_name0, + int field_name_len, int maybe_missing) +{ + char *field_name = alloca ((field_name_len + 1) * sizeof (char)); + + strncpy (field_name, field_name0, field_name_len); + field_name[field_name_len] = '\0'; + return ada_get_field_index (type, field_name, maybe_missing); +} + +/* If encoded_field_name is the name of a field inside symbol SYM, + then return the type of that field. Otherwise, return NULL. + + This function is actually recursive, so if ENCODED_FIELD_NAME + doesn't match one of the fields of our symbol, then try to see + if ENCODED_FIELD_NAME could not be a succession of field names + (in other words, the user entered an expression of the form + TYPE_NAME.FIELD1.FIELD2.FIELD3), in which case we evaluate + each field name sequentially to obtain the desired field type. + In case of failure, we return NULL. */ + +static struct type * +get_symbol_field_type (struct symbol *sym, char *encoded_field_name) +{ + char *field_name = encoded_field_name; + char *subfield_name; + struct type *type = SYMBOL_TYPE (sym); + int fieldno; + + if (type == NULL || field_name == NULL) + return NULL; + type = check_typedef (type); + + while (field_name[0] != '\0') + { + field_name = chop_separator (field_name); + + fieldno = ada_get_field_index (type, field_name, 1); + if (fieldno >= 0) + return TYPE_FIELD_TYPE (type, fieldno); + + subfield_name = field_name; + while (*subfield_name != '\0' && *subfield_name != '.' + && (subfield_name[0] != '_' || subfield_name[1] != '_')) + subfield_name += 1; + + if (subfield_name[0] == '\0') + return NULL; + + fieldno = ada_nget_field_index (type, field_name, + subfield_name - field_name, 1); + if (fieldno < 0) + return NULL; + + type = TYPE_FIELD_TYPE (type, fieldno); + field_name = subfield_name; + } + + return NULL; +} + +/* Look up NAME0 (an unencoded identifier or dotted name) in BLOCK (or + expression_block_context if NULL). If it denotes a type, return + that type. Otherwise, write expression code to evaluate it as an + object and return NULL. In this second case, NAME0 will, in general, + have the form (.)*, where is an object + or renaming encoded in the debugging data. Calls error if no + prefix matches a name in the debugging data (i.e., matches + either a complete name or, as a wild-card match, the final + identifier). */ + +static struct type* +write_var_or_type (const struct block *block, struct stoken name0) +{ + int depth; + char *encoded_name; + int name_len; + + if (block == NULL) + block = expression_context_block; + + encoded_name = ada_encode (name0.ptr); + name_len = strlen (encoded_name); + encoded_name = obstack_copy0 (&temp_parse_space, encoded_name, name_len); + for (depth = 0; depth < MAX_RENAMING_CHAIN_LENGTH; depth += 1) + { + int tail_index; + + tail_index = name_len; + while (tail_index > 0) + { + int nsyms; + struct ada_symbol_info *syms; + struct symbol *type_sym; + struct symbol *renaming_sym; + const char* renaming; + int renaming_len; + const char* renaming_expr; + int terminator = encoded_name[tail_index]; + + encoded_name[tail_index] = '\0'; + nsyms = ada_lookup_symbol_list (encoded_name, block, + VAR_DOMAIN, &syms); + encoded_name[tail_index] = terminator; + + /* A single symbol may rename a package or object. */ + + /* This should go away when we move entirely to new version. + FIXME pnh 7/20/2007. */ + if (nsyms == 1) + { + struct symbol *ren_sym = + ada_find_renaming_symbol (syms[0].sym, syms[0].block); + + if (ren_sym != NULL) + syms[0].sym = ren_sym; + } + + type_sym = select_possible_type_sym (syms, nsyms); + + if (type_sym != NULL) + renaming_sym = type_sym; + else if (nsyms == 1) + renaming_sym = syms[0].sym; + else + renaming_sym = NULL; + + switch (ada_parse_renaming (renaming_sym, &renaming, + &renaming_len, &renaming_expr)) + { + case ADA_NOT_RENAMING: + break; + case ADA_PACKAGE_RENAMING: + case ADA_EXCEPTION_RENAMING: + case ADA_SUBPROGRAM_RENAMING: + { + char *new_name + = obstack_alloc (&temp_parse_space, + renaming_len + name_len - tail_index + 1); + strncpy (new_name, renaming, renaming_len); + strcpy (new_name + renaming_len, encoded_name + tail_index); + encoded_name = new_name; + name_len = renaming_len + name_len - tail_index; + goto TryAfterRenaming; + } + case ADA_OBJECT_RENAMING: + write_object_renaming (block, renaming, renaming_len, + renaming_expr, MAX_RENAMING_CHAIN_LENGTH); + write_selectors (encoded_name + tail_index); + return NULL; + default: + internal_error (__FILE__, __LINE__, + _("impossible value from ada_parse_renaming")); + } + + if (type_sym != NULL) + { + struct type *field_type; + + if (tail_index == name_len) + return SYMBOL_TYPE (type_sym); + + /* We have some extraneous characters after the type name. + If this is an expression "TYPE_NAME.FIELD0.[...].FIELDN", + then try to get the type of FIELDN. */ + field_type + = get_symbol_field_type (type_sym, encoded_name + tail_index); + if (field_type != NULL) + return field_type; + else + error (_("Invalid attempt to select from type: \"%s\"."), + name0.ptr); + } + else if (tail_index == name_len && nsyms == 0) + { + struct type *type = find_primitive_type (encoded_name); + + if (type != NULL) + return type; + } + + if (nsyms == 1) + { + write_var_from_sym (block, syms[0].block, syms[0].sym); + write_selectors (encoded_name + tail_index); + return NULL; + } + else if (nsyms == 0) + { + struct minimal_symbol *msym + = ada_lookup_simple_minsym (encoded_name); + if (msym != NULL) + { + write_exp_msymbol (msym); + /* Maybe cause error here rather than later? FIXME? */ + write_selectors (encoded_name + tail_index); + return NULL; + } + + if (tail_index == name_len + && strncmp (encoded_name, "standard__", + sizeof ("standard__") - 1) == 0) + error (_("No definition of \"%s\" found."), name0.ptr); + + tail_index = chop_selector (encoded_name, tail_index); + } + else + { + write_ambiguous_var (block, encoded_name, tail_index); + write_selectors (encoded_name + tail_index); + return NULL; + } + } + + if (!have_full_symbols () && !have_partial_symbols () && block == NULL) + error (_("No symbol table is loaded. Use the \"file\" command.")); + if (block == expression_context_block) + error (_("No definition of \"%s\" in current context."), name0.ptr); + else + error (_("No definition of \"%s\" in specified context."), name0.ptr); + + TryAfterRenaming: ; + } + + error (_("Could not find renamed symbol \"%s\""), name0.ptr); + +} + +/* Write a left side of a component association (e.g., NAME in NAME => + exp). If NAME has the form of a selected component, write it as an + ordinary expression. If it is a simple variable that unambiguously + corresponds to exactly one symbol that does not denote a type or an + object renaming, also write it normally as an OP_VAR_VALUE. + Otherwise, write it as an OP_NAME. + + Unfortunately, we don't know at this point whether NAME is supposed + to denote a record component name or the value of an array index. + Therefore, it is not appropriate to disambiguate an ambiguous name + as we normally would, nor to replace a renaming with its referent. + As a result, in the (one hopes) rare case that one writes an + aggregate such as (R => 42) where R renames an object or is an + ambiguous name, one must write instead ((R) => 42). */ + +static void +write_name_assoc (struct stoken name) +{ + if (strchr (name.ptr, '.') == NULL) + { + struct ada_symbol_info *syms; + int nsyms = ada_lookup_symbol_list (name.ptr, expression_context_block, + VAR_DOMAIN, &syms); + if (nsyms != 1 || SYMBOL_CLASS (syms[0].sym) == LOC_TYPEDEF) + write_exp_op_with_string (OP_NAME, name); + else + write_var_from_sym (NULL, syms[0].block, syms[0].sym); + } + else + if (write_var_or_type (NULL, name) != NULL) + error (_("Invalid use of type.")); +} + +/* Convert the character literal whose ASCII value would be VAL to the + appropriate value of type TYPE, if there is a translation. + Otherwise return VAL. Hence, in an enumeration type ('A', 'B'), + the literal 'A' (VAL == 65), returns 0. */ + +static LONGEST +convert_char_literal (struct type *type, LONGEST val) +{ + char name[7]; + int f; + + if (type == NULL) + return val; + type = check_typedef (type); + if (TYPE_CODE (type) != TYPE_CODE_ENUM) + return val; + + xsnprintf (name, sizeof (name), "QU%02x", (int) val); + for (f = 0; f < TYPE_NFIELDS (type); f += 1) + { + if (strcmp (name, TYPE_FIELD_NAME (type, f)) == 0) + return TYPE_FIELD_ENUMVAL (type, f); + } + return val; +} + +static struct type * +type_int (void) +{ + return parse_type->builtin_int; +} + +static struct type * +type_long (void) +{ + return parse_type->builtin_long; +} + +static struct type * +type_long_long (void) +{ + return parse_type->builtin_long_long; +} + +static struct type * +type_float (void) +{ + return parse_type->builtin_float; +} + +static struct type * +type_double (void) +{ + return parse_type->builtin_double; +} + +static struct type * +type_long_double (void) +{ + return parse_type->builtin_long_double; +} + +static struct type * +type_char (void) +{ + return language_string_char_type (parse_language, parse_gdbarch); +} + +static struct type * +type_boolean (void) +{ + return parse_type->builtin_bool; +} + +static struct type * +type_system_address (void) +{ + struct type *type + = language_lookup_primitive_type_by_name (parse_language, + parse_gdbarch, + "system__address"); + return type != NULL ? type : parse_type->builtin_data_ptr; +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_ada_exp; + +void +_initialize_ada_exp (void) +{ + obstack_init (&temp_parse_space); +} + +/* FIXME: hilfingr/2004-10-05: Hack to remove warning. The function + string_to_operator is supposed to be used for cases where one + calls an operator function with prefix notation, as in + "+" (a, b), but at some point, this code seems to have gone + missing. */ + +struct stoken (*dummy_string_to_ada_operator) (struct stoken) + = string_to_operator; + diff --git a/contrib/gdb-7/gdb/ada-exp.y b/contrib/gdb-7/gdb/ada-exp.y index d8c21a4f11..d9fa9acd0c 100644 --- a/contrib/gdb-7/gdb/ada-exp.y +++ b/contrib/gdb-7/gdb/ada-exp.y @@ -1,6 +1,5 @@ /* YACC parser for Ada expressions, for GDB. - Copyright (C) 1986, 1989-1991, 1993-1994, 1997, 2000, 2003-2004, - 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -94,6 +93,12 @@ #define yytoks ada_toks /* With YYDEBUG defined */ #define yyname ada_name /* With YYDEBUG defined */ #define yyrule ada_rule /* With YYDEBUG defined */ +#define yyss ada_yyss +#define yysslim ada_yysslim +#define yyssp ada_yyssp +#define yystacksize ada_yystacksize +#define yyvs ada_yyvs +#define yyvsp ada_yyvsp #ifndef YYDEBUG #define YYDEBUG 1 /* Default to yydebug support */ @@ -124,10 +129,10 @@ static struct stoken string_to_operator (struct stoken); static void write_int (LONGEST, struct type *); -static void write_object_renaming (struct block *, const char *, int, +static void write_object_renaming (const struct block *, const char *, int, const char *, int); -static struct type* write_var_or_type (struct block *, struct stoken); +static struct type* write_var_or_type (const struct block *, struct stoken); static void write_name_assoc (struct stoken); @@ -137,7 +142,7 @@ static struct block *block_lookup (struct block *, char *); static LONGEST convert_char_literal (struct type *, LONGEST); -static void write_ambiguous_var (struct block *, char *, int); +static void write_ambiguous_var (const struct block *, char *, int); static struct type *type_int (void); @@ -812,8 +817,8 @@ string_to_operator (struct stoken string) /* Emit expression to access an instance of SYM, in block BLOCK (if * non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */ static void -write_var_from_sym (struct block *orig_left_context, - struct block *block, +write_var_from_sym (const struct block *orig_left_context, + const struct block *block, struct symbol *sym) { if (orig_left_context == NULL && symbol_read_needs_frame (sym)) @@ -861,14 +866,13 @@ write_exp_op_with_string (enum exp_opcode opcode, struct stoken token) * new encoding entirely (FIXME pnh 7/20/2007). */ static void -write_object_renaming (struct block *orig_left_context, +write_object_renaming (const struct block *orig_left_context, const char *renamed_entity, int renamed_entity_len, const char *renaming_expr, int max_depth) { char *name; enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state; - struct symbol *sym; - struct block *block; + struct ada_symbol_info sym_info; if (max_depth <= 0) error (_("Could not find renamed symbol")); @@ -876,30 +880,29 @@ write_object_renaming (struct block *orig_left_context, if (orig_left_context == NULL) orig_left_context = get_selected_block (NULL); - name = obsavestring (renamed_entity, renamed_entity_len, &temp_parse_space); - sym = ada_lookup_encoded_symbol (name, orig_left_context, VAR_DOMAIN, - &block); - if (sym == NULL) + name = obstack_copy0 (&temp_parse_space, renamed_entity, renamed_entity_len); + ada_lookup_encoded_symbol (name, orig_left_context, VAR_DOMAIN, &sym_info); + if (sym_info.sym == NULL) error (_("Could not find renamed variable: %s"), ada_decode (name)); - else if (SYMBOL_CLASS (sym) == LOC_TYPEDEF) + else if (SYMBOL_CLASS (sym_info.sym) == LOC_TYPEDEF) /* We have a renaming of an old-style renaming symbol. Don't trust the block information. */ - block = orig_left_context; + sym_info.block = orig_left_context; { const char *inner_renamed_entity; int inner_renamed_entity_len; const char *inner_renaming_expr; - switch (ada_parse_renaming (sym, &inner_renamed_entity, + switch (ada_parse_renaming (sym_info.sym, &inner_renamed_entity, &inner_renamed_entity_len, &inner_renaming_expr)) { case ADA_NOT_RENAMING: - write_var_from_sym (orig_left_context, block, sym); + write_var_from_sym (orig_left_context, sym_info.block, sym_info.sym); break; case ADA_OBJECT_RENAMING: - write_object_renaming (block, + write_object_renaming (sym_info.block, inner_renamed_entity, inner_renamed_entity_len, inner_renaming_expr, max_depth - 1); break; @@ -939,25 +942,26 @@ write_object_renaming (struct block *orig_left_context, { const char *end; char *index_name; - struct symbol *index_sym; + struct ada_symbol_info index_sym_info; end = strchr (renaming_expr, 'X'); if (end == NULL) end = renaming_expr + strlen (renaming_expr); index_name = - obsavestring (renaming_expr, end - renaming_expr, - &temp_parse_space); + obstack_copy0 (&temp_parse_space, renaming_expr, + end - renaming_expr); renaming_expr = end; - index_sym = ada_lookup_encoded_symbol (index_name, NULL, - VAR_DOMAIN, &block); - if (index_sym == NULL) + ada_lookup_encoded_symbol (index_name, NULL, VAR_DOMAIN, + &index_sym_info); + if (index_sym_info.sym == NULL) error (_("Could not find %s"), index_name); - else if (SYMBOL_CLASS (index_sym) == LOC_TYPEDEF) + else if (SYMBOL_CLASS (index_sym_info.sym) == LOC_TYPEDEF) /* Index is an old-style renaming symbol. */ - block = orig_left_context; - write_var_from_sym (NULL, block, index_sym); + index_sym_info.block = orig_left_context; + write_var_from_sym (NULL, index_sym_info.block, + index_sym_info.sym); } if (slice_state == SIMPLE_INDEX) { @@ -1156,13 +1160,13 @@ write_selectors (char *sels) a temporary symbol that is valid until the next call to ada_parse. */ static void -write_ambiguous_var (struct block *block, char *name, int len) +write_ambiguous_var (const struct block *block, char *name, int len) { struct symbol *sym = obstack_alloc (&temp_parse_space, sizeof (struct symbol)); memset (sym, 0, sizeof (struct symbol)); SYMBOL_DOMAIN (sym) = UNDEF_DOMAIN; - SYMBOL_LINKAGE_NAME (sym) = obsavestring (name, len, &temp_parse_space); + SYMBOL_LINKAGE_NAME (sym) = obstack_copy0 (&temp_parse_space, name, len); SYMBOL_LANGUAGE (sym) = language_ada; write_exp_elt_opcode (OP_VAR_VALUE); @@ -1248,7 +1252,7 @@ get_symbol_field_type (struct symbol *sym, char *encoded_field_name) identifier). */ static struct type* -write_var_or_type (struct block *block, struct stoken name0) +write_var_or_type (const struct block *block, struct stoken name0) { int depth; char *encoded_name; @@ -1259,7 +1263,7 @@ write_var_or_type (struct block *block, struct stoken name0) encoded_name = ada_encode (name0.ptr); name_len = strlen (encoded_name); - encoded_name = obsavestring (encoded_name, name_len, &temp_parse_space); + encoded_name = obstack_copy0 (&temp_parse_space, encoded_name, name_len); for (depth = 0; depth < MAX_RENAMING_CHAIN_LENGTH; depth += 1) { int tail_index; @@ -1288,8 +1292,7 @@ write_var_or_type (struct block *block, struct stoken name0) if (nsyms == 1) { struct symbol *ren_sym = - ada_find_renaming_symbol (SYMBOL_LINKAGE_NAME (syms[0].sym), - syms[0].block); + ada_find_renaming_symbol (syms[0].sym, syms[0].block); if (ren_sym != NULL) syms[0].sym = ren_sym; @@ -1459,7 +1462,7 @@ convert_char_literal (struct type *type, LONGEST val) for (f = 0; f < TYPE_NFIELDS (type); f += 1) { if (strcmp (name, TYPE_FIELD_NAME (type, f)) == 0) - return TYPE_FIELD_BITPOS (type, f); + return TYPE_FIELD_ENUMVAL (type, f); } return val; } diff --git a/contrib/gdb-7/gdb/ada-lang.c b/contrib/gdb-7/gdb/ada-lang.c index 2d81694789..63a85eeff3 100644 --- a/contrib/gdb-7/gdb/ada-lang.c +++ b/contrib/gdb-7/gdb/ada-lang.c @@ -1,7 +1,6 @@ /* Ada language support routines for GDB, the GNU debugger. - Copyright (C) 1992-1994, 1997-2000, 2003-2005, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -57,12 +56,15 @@ #include "observer.h" #include "vec.h" #include "stack.h" +#include "gdb_vecs.h" +#include "typeprint.h" #include "psymtab.h" #include "value.h" #include "mi/mi-common.h" #include "arch-utils.h" #include "exceptions.h" +#include "cli/cli-utils.h" /* Define whether or not the C operator '/' truncates towards zero for differently signed operands (truncation direction is undefined in C). @@ -125,7 +127,7 @@ static struct value *resolve_subexp (struct expression **, int *, int, struct type *); static void replace_operator_with_call (struct expression **, int, int, int, - struct symbol *, struct block *); + struct symbol *, const struct block *); static int possible_user_operator_p (enum exp_opcode, struct value **); @@ -147,7 +149,7 @@ static enum ada_renaming_category parse_old_style_renaming (struct type *, const char **); static struct symbol *find_old_style_renaming_symbol (const char *, - struct block *); + const struct block *); static struct type *ada_lookup_struct_elt_type (struct type *, char *, int, int, int *); @@ -221,7 +223,7 @@ static struct value *ada_search_struct_field (char *, struct value *, int, static struct value *ada_value_primitive_field (struct value *, int, int, struct type *); -static int find_struct_field (char *, struct type *, int, +static int find_struct_field (const char *, struct type *, int, struct type **, int *, int *, int *, int *); static struct value *ada_to_fixed_value_create (struct type *, CORE_ADDR, @@ -269,6 +271,8 @@ static struct value *ada_evaluate_subexp (struct type *, struct expression *, static void ada_forward_operator_length (struct expression *, int, int *, int *); + +static struct type *ada_find_any_type (const char *name); @@ -577,6 +581,7 @@ coerce_unspec_val_to_type (struct value *val, struct type *type) set_value_bitsize (result, value_bitsize (val)); set_value_bitpos (result, value_bitpos (val)); set_value_address (result, value_address (val)); + set_value_optimized_out (result, value_optimized_out (val)); return result; } } @@ -686,7 +691,7 @@ ada_discrete_type_high_bound (struct type *type) case TYPE_CODE_RANGE: return TYPE_HIGH_BOUND (type); case TYPE_CODE_ENUM: - return TYPE_FIELD_BITPOS (type, TYPE_NFIELDS (type) - 1); + return TYPE_FIELD_ENUMVAL (type, TYPE_NFIELDS (type) - 1); case TYPE_CODE_BOOL: return 1; case TYPE_CODE_CHAR: @@ -697,7 +702,7 @@ ada_discrete_type_high_bound (struct type *type) } } -/* The largest value in the domain of TYPE, a discrete type, as an integer. */ +/* The smallest value in the domain of TYPE, a discrete type, as an integer. */ LONGEST ada_discrete_type_low_bound (struct type *type) { @@ -706,7 +711,7 @@ ada_discrete_type_low_bound (struct type *type) case TYPE_CODE_RANGE: return TYPE_LOW_BOUND (type); case TYPE_CODE_ENUM: - return TYPE_FIELD_BITPOS (type, 0); + return TYPE_FIELD_ENUMVAL (type, 0); case TYPE_CODE_BOOL: return 0; case TYPE_CODE_CHAR: @@ -731,6 +736,46 @@ get_base_type (struct type *type) } return type; } + +/* Return a decoded version of the given VALUE. This means returning + a value whose type is obtained by applying all the GNAT-specific + encondings, making the resulting type a static but standard description + of the initial type. */ + +struct value * +ada_get_decoded_value (struct value *value) +{ + struct type *type = ada_check_typedef (value_type (value)); + + if (ada_is_array_descriptor_type (type) + || (ada_is_constrained_packed_array_type (type) + && TYPE_CODE (type) != TYPE_CODE_PTR)) + { + if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) /* array access type. */ + value = ada_coerce_to_simple_array_ptr (value); + else + value = ada_coerce_to_simple_array (value); + } + else + value = ada_to_fixed_value (value); + + return value; +} + +/* Same as ada_get_decoded_value, but with the given TYPE. + Because there is no associated actual value for this type, + the resulting type might be a best-effort approximation in + the case of dynamic types. */ + +struct type * +ada_get_decoded_type (struct type *type) +{ + type = to_static_fixed_type (type); + if (ada_is_constrained_packed_array_type (type)) + type = ada_coerce_to_simple_array_type (type); + return type; +} + /* Language Selection */ @@ -1251,11 +1296,11 @@ static struct htab *decoded_names_store; const, but nevertheless modified to a semantically equivalent form when a decoded name is cached in it. */ -char * +const char * ada_decode_symbol (const struct general_symbol_info *gsymbol) { - char **resultp = - (char **) &gsymbol->language_specific.mangled_lang.demangled_name; + const char **resultp = + (const char **) &gsymbol->language_specific.mangled_lang.demangled_name; if (*resultp == NULL) { @@ -1265,8 +1310,8 @@ ada_decode_symbol (const struct general_symbol_info *gsymbol) { struct objfile *objf = gsymbol->obj_section->objfile; - *resultp = obsavestring (decoded, strlen (decoded), - &objf->objfile_obstack); + *resultp = obstack_copy0 (&objf->objfile_obstack, + decoded, strlen (decoded)); } /* Sometimes, we can't find a corresponding objfile, in which case, we put the result on the heap. Since we only decode @@ -1368,7 +1413,7 @@ ada_fixup_array_indexes_type (struct type *index_desc_type) /* Fixup each field of INDEX_DESC_TYPE. */ for (i = 0; i < TYPE_NFIELDS (index_desc_type); i++) { - char *name = TYPE_FIELD_NAME (index_desc_type, i); + const char *name = TYPE_FIELD_NAME (index_desc_type, i); struct type *raw_type = ada_check_typedef (ada_find_any_type (name)); if (raw_type) @@ -1960,8 +2005,8 @@ ada_is_unconstrained_packed_array_type (struct type *type) static long decode_packed_array_bitsize (struct type *type) { - char *raw_name; - char *tail; + const char *raw_name; + const char *tail; long bits; /* Access to arrays implemented as fat pointers are encoded as a typedef @@ -2004,22 +2049,30 @@ constrained_packed_array_type (struct type *type, long *elt_bits) { struct type *new_elt_type; struct type *new_type; + struct type *index_type_desc; + struct type *index_type; LONGEST low_bound, high_bound; type = ada_check_typedef (type); if (TYPE_CODE (type) != TYPE_CODE_ARRAY) return type; + index_type_desc = ada_find_parallel_type (type, "___XA"); + if (index_type_desc) + index_type = to_fixed_range_type (TYPE_FIELD_TYPE (index_type_desc, 0), + NULL); + else + index_type = TYPE_INDEX_TYPE (type); + new_type = alloc_type_copy (type); new_elt_type = constrained_packed_array_type (ada_check_typedef (TYPE_TARGET_TYPE (type)), elt_bits); - create_array_type (new_type, new_elt_type, TYPE_INDEX_TYPE (type)); + create_array_type (new_type, new_elt_type, index_type); TYPE_FIELD_BITSIZE (new_type, 0) = *elt_bits; TYPE_NAME (new_type) = ada_type_name (type); - if (get_discrete_bounds (TYPE_INDEX_TYPE (type), - &low_bound, &high_bound) < 0) + if (get_discrete_bounds (index_type, &low_bound, &high_bound) < 0) low_bound = high_bound = 0; if (high_bound < low_bound) *elt_bits = TYPE_LENGTH (new_type) = 0; @@ -2040,9 +2093,9 @@ constrained_packed_array_type (struct type *type, long *elt_bits) static struct type * decode_constrained_packed_array_type (struct type *type) { - char *raw_name = ada_type_name (ada_check_typedef (type)); + const char *raw_name = ada_type_name (ada_check_typedef (type)); char *name; - char *tail; + const char *tail; struct type *shadow_type; long bits; @@ -2245,10 +2298,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) + offset); + v = value_at (type, value_address (obj)); bytes = (unsigned char *) alloca (len); - read_memory (value_address (v), bytes, len); + read_memory (value_address (v) + offset, bytes, len); } else { @@ -2258,18 +2310,22 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr, if (obj != NULL) { - CORE_ADDR new_addr; + long new_offset = offset; set_value_component_location (v, obj); - 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) { - ++new_addr; + ++new_offset; set_value_bitpos (v, value_bitpos (v) - HOST_CHAR_BIT); } - set_value_address (v, new_addr); + set_value_offset (v, new_offset); + + /* Also set the parent value. This is needed when trying to + assign a new value (in inferior memory). */ + set_value_parent (v, obj); + value_incref (obj); } else set_value_bitsize (v, bit_size); @@ -2479,8 +2535,7 @@ ada_value_assign (struct value *toval, struct value *fromval) else move_bits (buffer, value_bitpos (toval), value_contents (fromval), 0, bits, 0); - write_memory (to_addr, buffer, len); - observer_notify_memory_changed (to_addr, len, buffer); + write_memory_with_notification (to_addr, buffer, len); val = value_copy (toval); memcpy (value_contents_raw (val), value_contents (fromval), @@ -3405,7 +3460,7 @@ ada_resolve_function (struct ada_symbol_info syms[], such symbols by their trailing number (__N or $N). */ static int -encoded_ordered_before (char *N0, char *N1) +encoded_ordered_before (const char *N0, const char *N1) { if (N1 == NULL) return 0; @@ -3518,7 +3573,8 @@ See set/show multiple-symbol.")); else printf_unfiltered (_("[%d] %s at %s:%d\n"), i + first_choice, SYMBOL_PRINT_NAME (syms[i].sym), - sal.symtab->filename, sal.line); + symtab_to_filename_for_display (sal.symtab), + sal.line); continue; } else @@ -3527,19 +3583,20 @@ See set/show multiple-symbol.")); (SYMBOL_CLASS (syms[i].sym) == LOC_CONST && SYMBOL_TYPE (syms[i].sym) != NULL && TYPE_CODE (SYMBOL_TYPE (syms[i].sym)) == TYPE_CODE_ENUM); - struct symtab *symtab = syms[i].sym->symtab; + struct symtab *symtab = SYMBOL_SYMTAB (syms[i].sym); if (SYMBOL_LINE (syms[i].sym) != 0 && symtab != NULL) printf_unfiltered (_("[%d] %s at %s:%d\n"), i + first_choice, SYMBOL_PRINT_NAME (syms[i].sym), - symtab->filename, SYMBOL_LINE (syms[i].sym)); + symtab_to_filename_for_display (symtab), + SYMBOL_LINE (syms[i].sym)); else if (is_enumeral && TYPE_NAME (SYMBOL_TYPE (syms[i].sym)) != NULL) { printf_unfiltered (("[%d] "), i + first_choice); ada_print_type (SYMBOL_TYPE (syms[i].sym), NULL, - gdb_stdout, -1, 0); + gdb_stdout, -1, 0, &type_print_raw_options); printf_unfiltered (_("'(%s) (enumeral)\n"), SYMBOL_PRINT_NAME (syms[i].sym)); } @@ -3549,7 +3606,7 @@ See set/show multiple-symbol.")); : _("[%d] %s at %s:?\n"), i + first_choice, SYMBOL_PRINT_NAME (syms[i].sym), - symtab->filename); + symtab_to_filename_for_display (symtab)); else printf_unfiltered (is_enumeral ? _("[%d] %s (enumeral)\n") @@ -3611,8 +3668,7 @@ get_selections (int *choices, int n_choices, int max_results, char *args2; int choice, j; - while (isspace (*args)) - args += 1; + args = skip_spaces (args); if (*args == '\0' && n_chosen == 0) error_no_arg (_("one or more choice numbers")); else if (*args == '\0') @@ -3664,7 +3720,7 @@ get_selections (int *choices, int n_choices, int max_results, static void replace_operator_with_call (struct expression **expp, int pc, int nargs, int oplen, struct symbol *sym, - struct block *block) + const struct block *block) { /* A new expression, with 6 more elements (3 for funcall, 4 for function symbol, -oplen for operator being replaced). */ @@ -3990,8 +4046,29 @@ parse_old_style_renaming (struct type *type, if (len != NULL) *len = suffix - info; return kind; -} +} + +/* Compute the value of the given RENAMING_SYM, which is expected to + be a symbol encoding a renaming expression. BLOCK is the block + used to evaluate the renaming. */ + +static struct value * +ada_read_renaming_var_value (struct symbol *renaming_sym, + struct block *block) +{ + const char *sym_name; + struct expression *expr; + struct value *value; + struct cleanup *old_chain = NULL; + + sym_name = SYMBOL_LINKAGE_NAME (renaming_sym); + expr = parse_exp_1 (&sym_name, 0, block, 0); + old_chain = make_cleanup (free_current_contents, &expr); + value = evaluate_expression (expr); + do_cleanups (old_chain); + return value; +} /* Evaluation: Function Calls */ @@ -4063,7 +4140,7 @@ ada_convert_actual (struct value *actual, struct type *formal_type0) } else return actual; - return value_cast_pointers (formal_type, result); + return value_cast_pointers (formal_type, result, 0); } else if (TYPE_CODE (actual_type) == TYPE_CODE_PTR) return ada_value_ind (actual); @@ -4155,12 +4232,24 @@ lookup_cached_symbol (const char *name, domain_enum namespace, static void cache_symbol (const char *name, domain_enum namespace, struct symbol *sym, - struct block *block) + const struct block *block) { } /* Symbol Lookup */ +/* Return nonzero if wild matching should be used when searching for + all symbols matching LOOKUP_NAME. + + LOOKUP_NAME is expected to be a symbol name after transformation + for Ada lookups (see ada_name_for_lookup). */ + +static int +should_use_wild_match (const char *lookup_name) +{ + return (strstr (lookup_name, "__") == NULL); +} + /* Return the result of a standard (literal, C-like) lookup of NAME in given DOMAIN, visible from lexical block BLOCK. */ @@ -4168,7 +4257,8 @@ static struct symbol * standard_lookup (const char *name, const struct block *block, domain_enum domain) { - struct symbol *sym; + /* Initialize it just to avoid a GCC false warning. */ + struct symbol *sym = NULL; if (lookup_cached_symbol (name, domain, &sym, NULL)) return sym; @@ -4235,8 +4325,8 @@ lesseq_defined_than (struct symbol *sym0, struct symbol *sym1) { struct type *type0 = SYMBOL_TYPE (sym0); struct type *type1 = SYMBOL_TYPE (sym1); - char *name0 = SYMBOL_LINKAGE_NAME (sym0); - char *name1 = SYMBOL_LINKAGE_NAME (sym1); + const char *name0 = SYMBOL_LINKAGE_NAME (sym0); + const char *name1 = SYMBOL_LINKAGE_NAME (sym1); int len0 = strlen (name0); return @@ -4317,8 +4407,8 @@ defns_collected (struct obstack *obstackp, int finish) } /* Return a minimal symbol matching NAME according to Ada decoding - rules. Returns NULL if there is no such minimal symbol. Names - prefixed with "standard__" are handled specially: "standard__" is + rules. Returns NULL if there is no such minimal symbol. Names + prefixed with "standard__" are handled specially: "standard__" is first stripped off, and only static and global symbols are searched. */ struct minimal_symbol * @@ -4326,19 +4416,21 @@ ada_lookup_simple_minsym (const char *name) { struct objfile *objfile; struct minimal_symbol *msymbol; - int wild_match; + const int wild_match_p = should_use_wild_match (name); + /* Special case: If the user specifies a symbol name inside package + Standard, do a non-wild matching of the symbol name without + the "standard__" prefix. This was primarily introduced in order + to allow the user to specifically access the standard exceptions + using, for instance, Standard.Constraint_Error when Constraint_Error + is ambiguous (due to the user defining its own Constraint_Error + entity inside its program). */ if (strncmp (name, "standard__", sizeof ("standard__") - 1) == 0) - { - name += sizeof ("standard__") - 1; - wild_match = 0; - } - else - wild_match = (strstr (name, "__") == NULL); + name += sizeof ("standard__") - 1; ALL_MSYMBOLS (objfile, msymbol) { - if (match_name (SYMBOL_LINKAGE_NAME (msymbol), name, wild_match) + if (match_name (SYMBOL_LINKAGE_NAME (msymbol), name, wild_match_p) && MSYMBOL_TYPE (msymbol) != mst_solib_trampoline) return msymbol; } @@ -4349,13 +4441,13 @@ ada_lookup_simple_minsym (const char *name) /* For all subprograms that statically enclose the subprogram of the selected frame, add symbols matching identifier NAME in DOMAIN and their blocks to the list of data in OBSTACKP, as for - ada_add_block_symbols (q.v.). If WILD, treat as NAME with a - wildcard prefix. */ + ada_add_block_symbols (q.v.). If WILD_MATCH_P, treat as NAME + with a wildcard prefix. */ static void add_symbols_from_enclosing_procs (struct obstack *obstackp, const char *name, domain_enum namespace, - int wild_match) + int wild_match_p) { } @@ -4365,7 +4457,7 @@ add_symbols_from_enclosing_procs (struct obstack *obstackp, static int is_nondebugging_type (struct type *type) { - char *name = ada_type_name (type); + const char *name = ada_type_name (type); return (name != NULL && strcmp (name, "") == 0); } @@ -4389,15 +4481,15 @@ ada_identical_enum_types_p (struct type *type1, struct type *type2) /* All enums in the type should have an identical underlying value. */ for (i = 0; i < TYPE_NFIELDS (type1); i++) - if (TYPE_FIELD_BITPOS (type1, i) != TYPE_FIELD_BITPOS (type2, i)) + if (TYPE_FIELD_ENUMVAL (type1, i) != TYPE_FIELD_ENUMVAL (type2, i)) return 0; /* All enumerals should also have the same name (modulo any numerical suffix). */ for (i = 0; i < TYPE_NFIELDS (type1); i++) { - char *name_1 = TYPE_FIELD_NAME (type1, i); - char *name_2 = TYPE_FIELD_NAME (type2, i); + const char *name_1 = TYPE_FIELD_NAME (type1, i); + const char *name_2 = TYPE_FIELD_NAME (type2, i); int len_1 = strlen (name_1); int len_2 = strlen (name_2); @@ -4632,7 +4724,7 @@ is_package_name (const char *name) not visible from FUNCTION_NAME. */ static int -old_renaming_is_invisible (const struct symbol *sym, char *function_name) +old_renaming_is_invisible (const struct symbol *sym, const char *function_name) { char *scope; @@ -4702,7 +4794,7 @@ remove_irrelevant_renamings (struct ada_symbol_info *syms, int nsyms, const struct block *current_block) { struct symbol *current_function; - char *current_function_name; + const char *current_function_name; int i; int is_new_style_renaming; @@ -4713,7 +4805,7 @@ remove_irrelevant_renamings (struct ada_symbol_info *syms, for (i = 0; i < nsyms; i += 1) { struct symbol *sym = syms[i].sym; - struct block *block = syms[i].block; + const struct block *block = syms[i].block; const char *name; const char *suffix; @@ -4792,20 +4884,23 @@ remove_irrelevant_renamings (struct ada_symbol_info *syms, If no match was found, then extend the search to "enclosing" routines (in other words, if we're inside a nested function, search the symbols defined inside the enclosing functions). + If WILD_MATCH_P is nonzero, perform the naming matching in + "wild" mode (see function "wild_match" for more info). Note: This function assumes that OBSTACKP has 0 (zero) element in it. */ static void ada_add_local_symbols (struct obstack *obstackp, const char *name, struct block *block, domain_enum domain, - int wild_match) + int wild_match_p) { int block_depth = 0; while (block != NULL) { block_depth += 1; - ada_add_block_symbols (obstackp, block, name, domain, NULL, wild_match); + ada_add_block_symbols (obstackp, block, name, domain, NULL, + wild_match_p); /* If we found a non-function match, assume that's the one. */ if (is_nonfunction (defns_collected (obstackp, 0), @@ -4818,7 +4913,7 @@ ada_add_local_symbols (struct obstack *obstackp, const char *name, /* If no luck so far, try to find NAME as a local symbol in some lexically enclosing subprogram. */ if (num_defns_collected (obstackp) == 0 && block_depth > 2) - add_symbols_from_enclosing_procs (obstackp, name, domain, wild_match); + add_symbols_from_enclosing_procs (obstackp, name, domain, wild_match_p); } /* An object of this type is used as the user_data argument when @@ -4922,8 +5017,8 @@ add_nonlocal_symbols (struct obstack *obstackp, const char *name, struct objfile *objfile; struct match_data data; + memset (&data, 0, sizeof data); data.obstackp = obstackp; - data.arg_sym = NULL; ALL_OBJFILES (objfile) { @@ -4956,29 +5051,33 @@ add_nonlocal_symbols (struct obstack *obstackp, const char *name, } } -/* Find symbols in DOMAIN matching NAME0, in BLOCK0 and enclosing - scope and in global scopes, returning the number of matches. Sets - *RESULTS to point to a vector of (SYM,BLOCK) tuples, +/* Find symbols in DOMAIN matching NAME0, in BLOCK0 and, if full_search is + non-zero, enclosing scope and in global scopes, returning the number of + matches. + Sets *RESULTS to point to a vector of (SYM,BLOCK) tuples, indicating the symbols found and the blocks and symbol tables (if - any) in which they were found. This vector are transient---good only to - the next call of ada_lookup_symbol_list. Any non-function/non-enumeral + any) in which they were found. This vector is transient---good only to + the next call of ada_lookup_symbol_list. + + When full_search is non-zero, any non-function/non-enumeral symbol match within the nest of blocks whose innermost member is BLOCK0, is the one match returned (no other matches in that or - enclosing blocks is returned). If there are any matches in or - surrounding BLOCK0, then these alone are returned. Otherwise, the - search extends to global and file-scope (static) symbol tables. - Names prefixed with "standard__" are handled specially: "standard__" + enclosing blocks is returned). If there are any matches in or + surrounding BLOCK0, then these alone are returned. + + Names prefixed with "standard__" are handled specially: "standard__" is first stripped off, and only static and global symbols are searched. */ -int -ada_lookup_symbol_list (const char *name0, const struct block *block0, - domain_enum namespace, - struct ada_symbol_info **results) +static int +ada_lookup_symbol_list_worker (const char *name0, const struct block *block0, + domain_enum namespace, + struct ada_symbol_info **results, + int full_search) { struct symbol *sym; struct block *block; const char *name; - int wild_match; + const int wild_match_p = should_use_wild_match (name0); int cacheIfUnique; int ndefns; @@ -4989,7 +5088,6 @@ ada_lookup_symbol_list (const char *name0, const struct block *block0, /* Search specified block and its superiors. */ - wild_match = (strstr (name0, "__") == NULL); name = name0; block = (struct block *) block0; /* FIXME: No cast ought to be needed, but adding const will @@ -5004,17 +5102,30 @@ ada_lookup_symbol_list (const char *name0, const struct block *block0, entity inside its program). */ if (strncmp (name0, "standard__", sizeof ("standard__") - 1) == 0) { - wild_match = 0; block = NULL; name = name0 + sizeof ("standard__") - 1; } /* Check the non-global symbols. If we have ANY match, then we're done. */ - ada_add_local_symbols (&symbol_list_obstack, name, block, namespace, - wild_match); - if (num_defns_collected (&symbol_list_obstack) > 0) - goto done; + if (block != NULL) + { + if (full_search) + { + ada_add_local_symbols (&symbol_list_obstack, name, block, + namespace, wild_match_p); + } + else + { + /* In the !full_search case we're are being called by + ada_iterate_over_symbols, and we don't want to search + superblocks. */ + ada_add_block_symbols (&symbol_list_obstack, block, name, + namespace, NULL, wild_match_p); + } + if (num_defns_collected (&symbol_list_obstack) > 0 || !full_search) + goto done; + } /* No non-global symbols found. Check our cache to see if we have already performed this search before. If we have, then return @@ -5031,14 +5142,14 @@ ada_lookup_symbol_list (const char *name0, const struct block *block0, /* Search symbols from all global blocks. */ add_nonlocal_symbols (&symbol_list_obstack, name, namespace, 1, - wild_match); + wild_match_p); /* Now add symbols from all per-file blocks if we've gotten no hits (not strictly correct, but perhaps better than an error). */ if (num_defns_collected (&symbol_list_obstack) == 0) add_nonlocal_symbols (&symbol_list_obstack, name, namespace, 0, - wild_match); + wild_match_p); done: ndefns = num_defns_collected (&symbol_list_obstack); @@ -5046,10 +5157,10 @@ done: ndefns = remove_extra_symbols (*results, ndefns); - if (ndefns == 0) + if (ndefns == 0 && full_search) cache_symbol (name0, namespace, NULL, NULL); - if (ndefns == 1 && cacheIfUnique) + if (ndefns == 1 && full_search && cacheIfUnique) cache_symbol (name0, namespace, (*results)[0].sym, (*results)[0].block); ndefns = remove_irrelevant_renamings (*results, ndefns, block0); @@ -5057,6 +5168,37 @@ done: return ndefns; } +/* Find symbols in DOMAIN matching NAME0, in BLOCK0 and enclosing scope and + in global scopes, returning the number of matches, and setting *RESULTS + to a vector of (SYM,BLOCK) tuples. + See ada_lookup_symbol_list_worker for further details. */ + +int +ada_lookup_symbol_list (const char *name0, const struct block *block0, + domain_enum domain, struct ada_symbol_info **results) +{ + return ada_lookup_symbol_list_worker (name0, block0, domain, results, 1); +} + +/* Implementation of the la_iterate_over_symbols method. */ + +static void +ada_iterate_over_symbols (const struct block *block, + const char *name, domain_enum domain, + symbol_found_callback_ftype *callback, + void *data) +{ + int ndefs, i; + struct ada_symbol_info *results; + + ndefs = ada_lookup_symbol_list_worker (name, block, domain, &results, 0); + for (i = 0; i < ndefs; ++i) + { + if (! (*callback) (results[i].sym, data)) + break; + } +} + /* If NAME is the name of an entity, return a string that should be used to look that entity up in Ada units. This string should be deallocated after use using xfree. @@ -5082,60 +5224,50 @@ ada_name_for_lookup (const char *name) return canon; } -/* Implementation of the la_iterate_over_symbols method. */ +/* The result is as for ada_lookup_symbol_list with FULL_SEARCH set + to 1, but choosing the first symbol found if there are multiple + choices. -static void -ada_iterate_over_symbols (const struct block *block, - const char *name, domain_enum domain, - int (*callback) (struct symbol *, void *), - void *data) -{ - int ndefs, i; - struct ada_symbol_info *results; + The result is stored in *INFO, which must be non-NULL. + If no match is found, INFO->SYM is set to NULL. */ - ndefs = ada_lookup_symbol_list (name, block, domain, &results); - for (i = 0; i < ndefs; ++i) - { - if (! (*callback) (results[i].sym, data)) - break; - } -} - -struct symbol * -ada_lookup_encoded_symbol (const char *name, const struct block *block0, - domain_enum namespace, struct block **block_found) +void +ada_lookup_encoded_symbol (const char *name, const struct block *block, + domain_enum namespace, + struct ada_symbol_info *info) { struct ada_symbol_info *candidates; int n_candidates; - n_candidates = ada_lookup_symbol_list (name, block0, namespace, &candidates); + gdb_assert (info != NULL); + memset (info, 0, sizeof (struct ada_symbol_info)); + n_candidates = ada_lookup_symbol_list (name, block, namespace, &candidates); if (n_candidates == 0) - return NULL; - - if (block_found != NULL) - *block_found = candidates[0].block; + return; - return fixup_symbol_section (candidates[0].sym, NULL); -} + *info = candidates[0]; + info->sym = fixup_symbol_section (info->sym, NULL); +} /* Return a symbol in DOMAIN matching NAME, in BLOCK0 and enclosing scope and in global scopes, or NULL if none. NAME is folded and encoded first. Otherwise, the result is as for ada_lookup_symbol_list, choosing the first symbol if there are multiple choices. - *IS_A_FIELD_OF_THIS is set to 0 and *SYMTAB is set to the symbol - table in which the symbol was found (in both cases, these - assignments occur only if the pointers are non-null). */ + If IS_A_FIELD_OF_THIS is not NULL, it is set to zero. */ + struct symbol * ada_lookup_symbol (const char *name, const struct block *block0, domain_enum namespace, int *is_a_field_of_this) { + struct ada_symbol_info info; + if (is_a_field_of_this != NULL) *is_a_field_of_this = 0; - return - ada_lookup_encoded_symbol (ada_encode (ada_fold_name (name)), - block0, namespace, NULL); + ada_lookup_encoded_symbol (ada_encode (ada_fold_name (name)), + block0, namespace, &info); + return info.sym; } static struct symbol * @@ -5154,6 +5286,7 @@ ada_lookup_symbol_nonlocal (const char *name, [.$][0-9]+ [nested subprogram suffix, on platforms such as GNU/Linux] ___[0-9]+ [nested subprogram suffix, on platforms such as HP/UX] + TKB [subprogram suffix for task bodies] _E[0-9]+[bs]$ [protected object entry suffixes] (X[nb]*)?((\$|__)[0-9](_?[0-9]+)|___(JM|LJM|X([FDBUP].*|R[^T]?)))?$ @@ -5199,6 +5332,11 @@ is_name_suffix (const char *str) return 1; } + /* "TKB" suffixes are used for subprograms implementing task bodies. */ + + if (strcmp (str, "TKB") == 0) + return 1; + #if 0 /* FIXME: brobecker/2005-09-23: Protected Object subprograms end with a N at the end. Unfortunately, the compiler uses the same @@ -5360,7 +5498,7 @@ advance_wild_match (const char **namep, const char *name0, int target0) static int wild_match (const char *name, const char *patn) { - const char *p, *n; + const char *p; const char *name0 = name; while (1) @@ -5396,8 +5534,7 @@ full_match (const char *sym_name, const char *search_name) /* Add symbols from BLOCK matching identifier NAME in DOMAIN to vector *defn_symbols, updating the list of symbols in OBSTACKP (if necessary). If WILD, treat as NAME with a wildcard prefix. - OBJFILE is the section containing BLOCK. - SYMTAB is recorded with each symbol added. */ + OBJFILE is the section containing BLOCK. */ static void ada_add_block_symbols (struct obstack *obstackp, @@ -5405,7 +5542,7 @@ ada_add_block_symbols (struct obstack *obstackp, domain_enum domain, struct objfile *objfile, int wild) { - struct dict_iterator iter; + struct block_iterator iter; int name_len = strlen (name); /* A matching argument symbol, if any. */ struct symbol *arg_sym; @@ -5417,9 +5554,8 @@ ada_add_block_symbols (struct obstack *obstackp, found_sym = 0; if (wild) { - for (sym = dict_iter_match_first (BLOCK_DICT (block), name, - wild_match, &iter); - sym != NULL; sym = dict_iter_match_next (name, wild_match, &iter)) + for (sym = block_iter_match_first (block, name, wild_match, &iter); + sym != NULL; sym = block_iter_match_next (name, wild_match, &iter)) { if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), SYMBOL_DOMAIN (sym), domain) @@ -5441,9 +5577,8 @@ ada_add_block_symbols (struct obstack *obstackp, } else { - for (sym = dict_iter_match_first (BLOCK_DICT (block), name, - full_match, &iter); - sym != NULL; sym = dict_iter_match_next (name, full_match, &iter)) + for (sym = block_iter_match_first (block, name, full_match, &iter); + sym != NULL; sym = block_iter_match_next (name, full_match, &iter)) { if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), SYMBOL_DOMAIN (sym), domain)) @@ -5530,14 +5665,14 @@ ada_add_block_symbols (struct obstack *obstackp, does not need to be deallocated, but is only good until the next call. TEXT_LEN is equal to the length of TEXT. - Perform a wild match if WILD_MATCH is set. - ENCODED should be set if TEXT represents the start of a symbol name + Perform a wild match if WILD_MATCH_P is set. + ENCODED_P should be set if TEXT represents the start of a symbol name in its encoded form. */ static const char * symbol_completion_match (const char *sym_name, const char *text, int text_len, - int wild_match, int encoded) + int wild_match_p, int encoded_p) { const int verbatim_match = (text[0] == '<'); int match = 0; @@ -5554,7 +5689,7 @@ symbol_completion_match (const char *sym_name, if (strncmp (sym_name, text, text_len) == 0) match = 1; - if (match && !encoded) + if (match && !encoded_p) { /* One needed check before declaring a positive match is to verify that iff we are doing a verbatim match, the decoded version @@ -5585,7 +5720,7 @@ symbol_completion_match (const char *sym_name, /* Second: Try wild matching... */ - if (!match && wild_match) + if (!match && wild_match_p) { /* Since we are doing wild matching, this means that TEXT may represent an unqualified symbol name. We therefore must @@ -5604,14 +5739,12 @@ symbol_completion_match (const char *sym_name, if (verbatim_match) sym_name = add_angle_brackets (sym_name); - if (!encoded) + if (!encoded_p) sym_name = ada_decode (sym_name); return sym_name; } -DEF_VEC_P (char_ptr); - /* A companion function to ada_make_symbol_completion_list(). Check if SYM_NAME represents a symbol which name would be suitable to complete TEXT (TEXT_LEN is the length of TEXT), in which case @@ -5622,8 +5755,8 @@ DEF_VEC_P (char_ptr); completion should be performed. These two parameters are used to determine which part of the symbol name should be added to the completion vector. - if WILD_MATCH is set, then wild matching is performed. - ENCODED should be set if TEXT represents a symbol name in its + if WILD_MATCH_P is set, then wild matching is performed. + ENCODED_P should be set if TEXT represents a symbol name in its encoded formed (in which case the completion should also be encoded). */ @@ -5632,10 +5765,10 @@ symbol_completion_add (VEC(char_ptr) **sv, const char *sym_name, const char *text, int text_len, const char *orig_text, const char *word, - int wild_match, int encoded) + int wild_match_p, int encoded_p) { const char *match = symbol_completion_match (sym_name, text, text_len, - wild_match, encoded); + wild_match_p, encoded_p); char *completion; if (match == NULL) @@ -5682,8 +5815,7 @@ struct add_partial_datum /* A callback for expand_partial_symbol_names. */ static int -ada_expand_partial_symbol_name (const struct language_defn *language, - const char *name, void *user_data) +ada_expand_partial_symbol_name (const char *name, void *user_data) { struct add_partial_datum *data = user_data; @@ -5691,17 +5823,16 @@ ada_expand_partial_symbol_name (const struct language_defn *language, data->wild_match, data->encoded) != NULL; } -/* Return a list of possible symbol names completing TEXT0. The list - is NULL terminated. WORD is the entire command on which completion - is made. */ +/* Return a list of possible symbol names completing TEXT0. WORD is + the entire command on which completion is made. */ -static char ** -ada_make_symbol_completion_list (char *text0, char *word) +static VEC (char_ptr) * +ada_make_symbol_completion_list (char *text0, char *word, enum type_code code) { char *text; int text_len; - int wild_match; - int encoded; + int wild_match_p; + int encoded_p; VEC(char_ptr) *completions = VEC_alloc (char_ptr, 128); struct symbol *sym; struct symtab *s; @@ -5709,15 +5840,17 @@ ada_make_symbol_completion_list (char *text0, char *word) struct objfile *objfile; struct block *b, *surrounding_static_block = 0; int i; - struct dict_iterator iter; + struct block_iterator iter; + + gdb_assert (code == TYPE_CODE_UNDEF); if (text0[0] == '<') { text = xstrdup (text0); make_cleanup (xfree, text); text_len = strlen (text); - wild_match = 0; - encoded = 1; + wild_match_p = 0; + encoded_p = 1; } else { @@ -5727,12 +5860,12 @@ ada_make_symbol_completion_list (char *text0, char *word) for (i = 0; i < text_len; i++) text[i] = tolower (text[i]); - encoded = (strstr (text0, "__") != NULL); + encoded_p = (strstr (text0, "__") != NULL); /* If the name contains a ".", then the user is entering a fully qualified entity name, and the match must not be done in wild mode. Similarly, if the user wants to complete what looks like an encoded name, the match must not be done in wild mode. */ - wild_match = (strchr (text0, '.') == NULL && !encoded); + wild_match_p = (strchr (text0, '.') == NULL && !encoded_p); } /* First, look at the partial symtab symbols. */ @@ -5744,8 +5877,8 @@ ada_make_symbol_completion_list (char *text0, char *word) data.text_len = text_len; data.text0 = text0; data.word = word; - data.wild_match = wild_match; - data.encoded = encoded; + data.wild_match = wild_match_p; + data.encoded = encoded_p; expand_partial_symbol_names (ada_expand_partial_symbol_name, &data); } @@ -5758,7 +5891,8 @@ ada_make_symbol_completion_list (char *text0, char *word) { QUIT; symbol_completion_add (&completions, SYMBOL_LINKAGE_NAME (msymbol), - text, text_len, text0, word, wild_match, encoded); + text, text_len, text0, word, wild_match_p, + encoded_p); } /* Search upwards from currently selected frame (so that we can @@ -5773,7 +5907,7 @@ ada_make_symbol_completion_list (char *text0, char *word) { symbol_completion_add (&completions, SYMBOL_LINKAGE_NAME (sym), text, text_len, text0, word, - wild_match, encoded); + wild_match_p, encoded_p); } } @@ -5788,7 +5922,7 @@ ada_make_symbol_completion_list (char *text0, char *word) { symbol_completion_add (&completions, SYMBOL_LINKAGE_NAME (sym), text, text_len, text0, word, - wild_match, encoded); + wild_match_p, encoded_p); } } @@ -5803,28 +5937,11 @@ ada_make_symbol_completion_list (char *text0, char *word) { symbol_completion_add (&completions, SYMBOL_LINKAGE_NAME (sym), text, text_len, text0, word, - wild_match, encoded); + wild_match_p, encoded_p); } } - /* Append the closing NULL entry. */ - VEC_safe_push (char_ptr, completions, NULL); - - /* Make a copy of the COMPLETIONS VEC before we free it, and then - return the copy. It's unfortunate that we have to make a copy - of an array that we're about to destroy, but there is nothing much - we can do about it. Fortunately, it's typically not a very large - array. */ - { - const size_t completions_size = - VEC_length (char_ptr, completions) * sizeof (char *); - char **result = xmalloc (completions_size); - - memcpy (result, VEC_address (char_ptr, completions), completions_size); - - VEC_free (char_ptr, completions); - return result; - } + return completions; } /* Field Access */ @@ -5835,7 +5952,7 @@ ada_make_symbol_completion_list (char *text0, char *word) static int ada_is_dispatch_table_ptr_type (struct type *type) { - char *name; + const char *name; if (TYPE_CODE (type) != TYPE_CODE_PTR) return 0; @@ -5847,6 +5964,19 @@ ada_is_dispatch_table_ptr_type (struct type *type) return (strcmp (name, "ada__tags__dispatch_table") == 0); } +/* Return non-zero if TYPE is an interface tag. */ + +static int +ada_is_interface_tag (struct type *type) +{ + const char *name = TYPE_NAME (type); + + if (name == NULL) + return 0; + + return (strcmp (name, "ada__tags__interface_tag") == 0); +} + /* True if field number FIELD_NUM in struct or union type TYPE is supposed to be invisible to users. */ @@ -5855,7 +5985,7 @@ ada_is_ignored_field (struct type *type, int field_num) { if (field_num < 0 || field_num > TYPE_NFIELDS (type)) return 1; - + /* Check the name of that field. */ { const char *name = TYPE_FIELD_NAME (type, field_num); @@ -5866,15 +5996,22 @@ ada_is_ignored_field (struct type *type, int field_num) if (name == NULL) return 1; - /* A field named "_parent" is internally generated by GNAT for - tagged types, and should not be printed either. */ + /* Normally, fields whose name start with an underscore ("_") + are fields that have been internally generated by the compiler, + and thus should not be printed. The "_parent" field is special, + however: This is a field internally generated by the compiler + for tagged types, and it contains the components inherited from + the parent type. This field should not be printed as is, but + should not be ignored either. */ if (name[0] == '_' && strncmp (name, "_parent", 7) != 0) return 1; } - /* If this is the dispatch table of a tagged type, then ignore. */ + /* If this is the dispatch table of a tagged type or an interface tag, + then ignore. */ if (ada_is_tagged_type (type, 1) - && ada_is_dispatch_table_ptr_type (TYPE_FIELD_TYPE (type, field_num))) + && (ada_is_dispatch_table_ptr_type (TYPE_FIELD_TYPE (type, field_num)) + || ada_is_interface_tag (TYPE_FIELD_TYPE (type, field_num)))) return 1; /* Not a special field, so it should not be ignored. */ @@ -5914,6 +6051,15 @@ ada_tag_type (struct value *val) return ada_lookup_struct_elt_type (value_type (val), "_tag", 1, 0, NULL); } +/* Return 1 if TAG follows the old scheme for Ada tags (used for Ada 95, + retired at Ada 05). */ + +static int +is_ada95_tag (struct value *tag) +{ + return ada_value_struct_elt (tag, "tsd", 1) != NULL; +} + /* The value of the tag on VAL. */ struct value * @@ -5957,42 +6103,86 @@ type_from_tag (struct value *tag) return NULL; } -struct tag_args +/* Given a value OBJ of a tagged type, return a value of this + type at the base address of the object. The base address, as + defined in Ada.Tags, it is the address of the primary tag of + the object, and therefore where the field values of its full + view can be fetched. */ + +struct value * +ada_tag_value_at_base_address (struct value *obj) { + volatile struct gdb_exception e; + struct value *val; + LONGEST offset_to_top = 0; + struct type *ptr_type, *obj_type; struct value *tag; - char *name; -}; + CORE_ADDR base_address; + obj_type = value_type (obj); -static int ada_tag_name_1 (void *); -static int ada_tag_name_2 (struct tag_args *); + /* It is the responsability of the caller to deref pointers. */ -/* Wrapper function used by ada_tag_name. Given a struct tag_args* - value ARGS, sets ARGS->name to the tag name of ARGS->tag. - The value stored in ARGS->name is valid until the next call to - ada_tag_name_1. */ + if (TYPE_CODE (obj_type) == TYPE_CODE_PTR + || TYPE_CODE (obj_type) == TYPE_CODE_REF) + return obj; -static int -ada_tag_name_1 (void *args0) -{ - struct tag_args *args = (struct tag_args *) args0; - static char name[1024]; - char *p; - struct value *val; + tag = ada_value_tag (obj); + if (!tag) + return obj; - args->name = NULL; - val = ada_value_struct_elt (args->tag, "tsd", 1); - if (val == NULL) - return ada_tag_name_2 (args); - val = ada_value_struct_elt (val, "expanded_name", 1); - if (val == NULL) - return 0; - read_memory_string (value_as_address (val), name, sizeof (name) - 1); - for (p = name; *p != '\0'; p += 1) - if (isalpha (*p)) - *p = tolower (*p); - args->name = name; - return 0; + /* Base addresses only appeared with Ada 05 and multiple inheritance. */ + + if (is_ada95_tag (tag)) + return obj; + + ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; + ptr_type = lookup_pointer_type (ptr_type); + val = value_cast (ptr_type, tag); + if (!val) + return obj; + + /* It is perfectly possible that an exception be raised while + trying to determine the base address, just like for the tag; + see ada_tag_name for more details. We do not print the error + message for the same reason. */ + + TRY_CATCH (e, RETURN_MASK_ERROR) + { + offset_to_top = value_as_long (value_ind (value_ptradd (val, -2))); + } + + if (e.reason < 0) + return obj; + + /* If offset is null, nothing to do. */ + + if (offset_to_top == 0) + return obj; + + /* -1 is a special case in Ada.Tags; however, what should be done + is not quite clear from the documentation. So do nothing for + now. */ + + if (offset_to_top == -1) + return obj; + + base_address = value_address (obj) - offset_to_top; + tag = value_tag_from_contents_and_address (obj_type, NULL, base_address); + + /* Make sure that we have a proper tag at the new address. + Otherwise, offset_to_top is bogus (which can happen when + the object is not initialized yet). */ + + if (!tag) + return obj; + + obj_type = type_from_tag (tag); + + if (!obj_type) + return obj; + + return value_from_contents_and_address (obj_type, NULL, base_address); } /* Return the "ada__tags__type_specific_data" type. */ @@ -6007,55 +6197,98 @@ ada_get_tsd_type (struct inferior *inf) return data->tsd_type; } -/* Utility function for ada_tag_name_1 that tries the second - representation for the dispatch table (in which there is no - explicit 'tsd' field in the referent of the tag pointer, and instead - the tsd pointer is stored just before the dispatch table. */ - -static int -ada_tag_name_2 (struct tag_args *args) +/* Return the TSD (type-specific data) associated to the given TAG. + TAG is assumed to be the tag of a tagged-type entity. + + May return NULL if we are unable to get the TSD. */ + +static struct value * +ada_get_tsd_from_tag (struct value *tag) +{ + struct value *val; + struct type *type; + + /* First option: The TSD is simply stored as a field of our TAG. + Only older versions of GNAT would use this format, but we have + to test it first, because there are no visible markers for + the current approach except the absence of that field. */ + + val = ada_value_struct_elt (tag, "tsd", 1); + if (val) + return val; + + /* Try the second representation for the dispatch table (in which + there is no explicit 'tsd' field in the referent of the tag pointer, + and instead the tsd pointer is stored just before the dispatch + table. */ + + type = ada_get_tsd_type (current_inferior()); + if (type == NULL) + return NULL; + type = lookup_pointer_type (lookup_pointer_type (type)); + val = value_cast (type, tag); + if (val == NULL) + return NULL; + return value_ind (value_ptradd (val, -1)); +} + +/* Given the TSD of a tag (type-specific data), return a string + containing the name of the associated type. + + The returned value is good until the next call. May return NULL + if we are unable to determine the tag name. */ + +static char * +ada_tag_name_from_tsd (struct value *tsd) { - struct type *info_type; static char name[1024]; char *p; - struct value *val, *valp; + struct value *val; - args->name = NULL; - info_type = ada_get_tsd_type (current_inferior()); - if (info_type == NULL) - return 0; - info_type = lookup_pointer_type (lookup_pointer_type (info_type)); - valp = value_cast (info_type, args->tag); - if (valp == NULL) - return 0; - val = value_ind (value_ptradd (valp, -1)); + val = ada_value_struct_elt (tsd, "expanded_name", 1); if (val == NULL) - return 0; - val = ada_value_struct_elt (val, "expanded_name", 1); - if (val == NULL) - return 0; + return NULL; read_memory_string (value_as_address (val), name, sizeof (name) - 1); for (p = name; *p != '\0'; p += 1) if (isalpha (*p)) *p = tolower (*p); - args->name = name; - return 0; + return name; } /* The type name of the dynamic type denoted by the 'tag value TAG, as - a C string. */ + a C string. + + Return NULL if the TAG is not an Ada tag, or if we were unable to + determine the name of that tag. The result is good until the next + call. */ const char * ada_tag_name (struct value *tag) { - struct tag_args args; + volatile struct gdb_exception e; + char *name = NULL; if (!ada_is_tag_type (value_type (tag))) return NULL; - args.tag = tag; - args.name = NULL; - catch_errors (ada_tag_name_1, &args, NULL, RETURN_MASK_ALL); - return args.name; + + /* It is perfectly possible that an exception be raised while trying + to determine the TAG's name, even under normal circumstances: + The associated variable may be uninitialized or corrupted, for + instance. We do not let any exception propagate past this point. + instead we return NULL. + + We also do not print the error message either (which often is very + low-level (Eg: "Cannot read memory at 0x[...]"), but instead let + the caller print a more meaningful message if necessary. */ + TRY_CATCH (e, RETURN_MASK_ERROR) + { + struct value *tsd = ada_get_tsd_from_tag (tag); + + if (tsd != NULL) + name = ada_tag_name_from_tsd (tsd); + } + + return name; } /* The parent type of TYPE, or NULL if none. */ @@ -6348,7 +6581,7 @@ ada_value_primitive_field (struct value *arg1, int offset, int fieldno, Returns 1 if found, 0 otherwise. */ static int -find_struct_field (char *name, struct type *type, int offset, +find_struct_field (const char *name, struct type *type, int offset, struct type **field_type_p, int *byte_offset_p, int *bit_offset_p, int *bit_size_p, int *index_p) @@ -6370,7 +6603,7 @@ find_struct_field (char *name, struct type *type, int offset, { int bit_pos = TYPE_FIELD_BITPOS (type, i); int fld_offset = offset + bit_pos / 8; - char *t_field_name = TYPE_FIELD_NAME (type, i); + const char *t_field_name = TYPE_FIELD_NAME (type, i); if (t_field_name == NULL) continue; @@ -6447,7 +6680,7 @@ ada_search_struct_field (char *name, struct value *arg, int offset, type = ada_check_typedef (type); for (i = 0; i < TYPE_NFIELDS (type); i += 1) { - char *t_field_name = TYPE_FIELD_NAME (type, i); + const char *t_field_name = TYPE_FIELD_NAME (type, i); if (t_field_name == NULL) continue; @@ -6607,9 +6840,9 @@ ada_value_struct_elt (struct value *arg, char *name, int no_err) CORE_ADDR address; if (TYPE_CODE (t) == TYPE_CODE_PTR) - address = value_as_address (arg); + address = value_address (ada_value_ind (arg)); else - address = unpack_pointer (t, value_contents (arg)); + address = value_address (ada_coerce_ref (arg)); t1 = ada_to_fixed_type (ada_get_base_type (t1), NULL, address, NULL, 1); if (find_struct_field (name, t1, 0, @@ -6706,7 +6939,7 @@ ada_lookup_struct_elt_type (struct type *type, char *name, int refok, for (i = 0; i < TYPE_NFIELDS (type); i += 1) { - char *t_field_name = TYPE_FIELD_NAME (type, i); + const char *t_field_name = TYPE_FIELD_NAME (type, i); struct type *t; int disp; @@ -6745,7 +6978,7 @@ ada_lookup_struct_elt_type (struct type *type, char *name, int refok, NOT wrapped in a struct, since the compiler sometimes generates these for unchecked variant types. Revisit if the compiler changes this practice. */ - char *v_field_name = TYPE_FIELD_NAME (field_type, j); + const char *v_field_name = TYPE_FIELD_NAME (field_type, j); disp = 0; if (v_field_name != NULL && field_name_match (v_field_name, name)) @@ -6883,7 +7116,10 @@ ada_which_variant_applies (struct type *var_type, struct type *outer_type, struct value * ada_value_ind (struct value *val0) { - struct value *val = unwrap_value (value_ind (val0)); + struct value *val = value_ind (val0); + + if (ada_is_tagged_type (value_type (val), 0)) + val = ada_tag_value_at_base_address (val); return ada_to_fixed_value (val); } @@ -6899,7 +7135,10 @@ ada_coerce_ref (struct value *val0) struct value *val = val0; val = coerce_ref (val); - val = unwrap_value (val); + + if (ada_is_tagged_type (value_type (val), 0)) + val = ada_tag_value_at_base_address (val); + return ada_to_fixed_value (val); } else @@ -6946,10 +7185,10 @@ field_alignment (struct type *type, int f) return atoi (name + align_offset) * TARGET_CHAR_BIT; } -/* Find a symbol named NAME. Ignores ambiguity. */ +/* Find a typedef or tag symbol named NAME. Ignores ambiguity. */ -struct symbol * -ada_find_any_symbol (const char *name) +static struct symbol * +ada_find_any_type_symbol (const char *name) { struct symbol *sym; @@ -6965,10 +7204,10 @@ ada_find_any_symbol (const char *name) solely for types defined by debug info, it will not search the GDB primitive types. */ -struct type * +static struct type * ada_find_any_type (const char *name) { - struct symbol *sym = ada_find_any_symbol (name); + struct symbol *sym = ada_find_any_type_symbol (name); if (sym != NULL) return SYMBOL_TYPE (sym); @@ -6976,23 +7215,28 @@ ada_find_any_type (const char *name) return NULL; } -/* Given NAME and an associated BLOCK, search all symbols for - NAME suffixed with "___XR", which is the ``renaming'' symbol - associated to NAME. Return this symbol if found, return - NULL otherwise. */ +/* Given NAME_SYM and an associated BLOCK, find a "renaming" symbol + associated with NAME_SYM's name. NAME_SYM may itself be a renaming + symbol, in which case it is returned. Otherwise, this looks for + symbols whose name is that of NAME_SYM suffixed with "___XR". + Return symbol if found, and NULL otherwise. */ struct symbol * -ada_find_renaming_symbol (const char *name, struct block *block) +ada_find_renaming_symbol (struct symbol *name_sym, const struct block *block) { + const char *name = SYMBOL_LINKAGE_NAME (name_sym); struct symbol *sym; + if (strstr (name, "___XR") != NULL) + return name_sym; + sym = find_old_style_renaming_symbol (name, block); if (sym != NULL) return sym; /* Not right yet. FIXME pnh 7/20/2007. */ - sym = ada_find_any_symbol (name); + sym = ada_find_any_type_symbol (name); if (sym != NULL && strstr (SYMBOL_LINKAGE_NAME (sym), "___XR") != NULL) return sym; else @@ -7000,7 +7244,7 @@ ada_find_renaming_symbol (const char *name, struct block *block) } static struct symbol * -find_old_style_renaming_symbol (const char *name, struct block *block) +find_old_style_renaming_symbol (const char *name, const struct block *block) { const struct symbol *function_sym = block_linkage_function (block); char *rename; @@ -7011,7 +7255,7 @@ find_old_style_renaming_symbol (const char *name, struct block *block) qualified. This means we need to prepend the function name as well as adding the ``___XR'' suffix to build the name of the associated renaming symbol. */ - char *function_name = SYMBOL_LINKAGE_NAME (function_sym); + const char *function_name = SYMBOL_LINKAGE_NAME (function_sym); /* Function names sometimes contain suffixes used for instance to qualify nested subprograms. When building the XR type name, we need to make sure that this suffix is @@ -7050,7 +7294,7 @@ find_old_style_renaming_symbol (const char *name, struct block *block) xsnprintf (rename, rename_len * sizeof (char), "%s___XR", name); } - return ada_find_any_symbol (rename); + return ada_find_any_type_symbol (rename); } /* Because of GNAT encoding conventions, several GDB symbols may match a @@ -7091,7 +7335,7 @@ ada_prefer_type (struct type *type0, struct type *type1) /* The name of TYPE, which is either its TYPE_NAME, or, if that is null, its TYPE_TAG_NAME. Null if TYPE is null. */ -char * +const char * ada_type_name (struct type *type) { if (type == NULL) @@ -7118,7 +7362,7 @@ find_parallel_type_by_descriptive_type (struct type *type, const char *name) result = TYPE_DESCRIPTIVE_TYPE (type); while (result != NULL) { - char *result_name = ada_type_name (result); + const char *result_name = ada_type_name (result); if (result_name == NULL) { @@ -7170,7 +7414,8 @@ ada_find_parallel_type_with_name (struct type *type, const char *name) struct type * ada_find_parallel_type (struct type *type, const char *suffix) { - char *name, *typename = ada_type_name (type); + char *name; + const char *typename = ada_type_name (type); int len; if (typename == NULL) @@ -7322,7 +7567,7 @@ ada_template_to_fixed_record_type_1 (struct type *type, { off = align_value (off, field_alignment (type, f)) + TYPE_FIELD_BITPOS (type, f); - TYPE_FIELD_BITPOS (rtype, f) = off; + SET_FIELD_BITPOS (TYPE_FIELD (rtype, f), off); TYPE_FIELD_BITSIZE (rtype, f) = 0; if (ada_is_variant_part (type, f)) @@ -7400,25 +7645,35 @@ ada_template_to_fixed_record_type_1 (struct type *type, } else { - struct type *field_type = TYPE_FIELD_TYPE (type, f); - - /* If our field is a typedef type (most likely a typedef of - a fat pointer, encoding an array access), then we need to - look at its target type to determine its characteristics. - In particular, we would miscompute the field size if we took - the size of the typedef (zero), instead of the size of - the target type. */ - if (TYPE_CODE (field_type) == TYPE_CODE_TYPEDEF) - field_type = ada_typedef_target_type (field_type); - - TYPE_FIELD_TYPE (rtype, f) = field_type; + /* Note: If this field's type is a typedef, it is important + to preserve the typedef layer. + + Otherwise, we might be transforming a typedef to a fat + pointer (encoding a pointer to an unconstrained array), + into a basic fat pointer (encoding an unconstrained + array). As both types are implemented using the same + structure, the typedef is the only clue which allows us + to distinguish between the two options. Stripping it + would prevent us from printing this field appropriately. */ + TYPE_FIELD_TYPE (rtype, f) = TYPE_FIELD_TYPE (type, f); TYPE_FIELD_NAME (rtype, f) = TYPE_FIELD_NAME (type, f); if (TYPE_FIELD_BITSIZE (type, f) > 0) fld_bit_len = TYPE_FIELD_BITSIZE (rtype, f) = TYPE_FIELD_BITSIZE (type, f); else - fld_bit_len = - TYPE_LENGTH (ada_check_typedef (field_type)) * TARGET_CHAR_BIT; + { + struct type *field_type = TYPE_FIELD_TYPE (type, f); + + /* We need to be careful of typedefs when computing + the length of our field. If this is a typedef, + get the length of the target type, not the length + of the typedef. */ + if (TYPE_CODE (field_type) == TYPE_CODE_TYPEDEF) + field_type = ada_typedef_target_type (field_type); + + fld_bit_len = + TYPE_LENGTH (ada_check_typedef (field_type)) * TARGET_CHAR_BIT; + } } if (off + fld_bit_len > bit_len) bit_len = off + fld_bit_len; @@ -7806,6 +8061,11 @@ to_fixed_array_type (struct type *type0, struct value *dval, error (_("array type with dynamic size is larger than varsize-limit")); } + /* We want to preserve the type name. This can be useful when + trying to get the type name of a value that has already been + printed (for instance, if the user did "print VAR; whatis $". */ + TYPE_NAME (result) = TYPE_NAME (type0); + if (constrained_packed_array_p) { /* So far, the resulting type has been created as if the original @@ -7862,21 +8122,27 @@ ada_to_fixed_type_1 (struct type *type, const gdb_byte *valaddr, if (check_tag && address != 0 && ada_is_tagged_type (static_type, 0)) { - struct type *real_type = - type_from_tag (value_tag_from_contents_and_address - (fixed_record_type, - valaddr, - address)); - + struct value *tag = + value_tag_from_contents_and_address + (fixed_record_type, + valaddr, + address); + struct type *real_type = type_from_tag (tag); + struct value *obj = + value_from_contents_and_address (fixed_record_type, + valaddr, + address); if (real_type != NULL) - return to_fixed_record_type (real_type, valaddr, address, NULL); + return to_fixed_record_type + (real_type, NULL, + value_address (ada_tag_value_at_base_address (obj)), NULL); } /* Check to see if there is a parallel ___XVZ variable. If there is, then it provides the actual size of our type. */ else if (ada_type_name (fixed_record_type) != NULL) { - char *name = ada_type_name (fixed_record_type); + const char *name = ada_type_name (fixed_record_type); char *xvz_name = alloca (strlen (name) + 7 /* "___XVZ\0" */); int xvz_found = 0; LONGEST size; @@ -8071,7 +8337,7 @@ ada_check_typedef (struct type *type) return type; else { - char *name = TYPE_TAG_NAME (type); + const char *name = TYPE_TAG_NAME (type); struct type *type1 = ada_find_any_type (name); if (type1 == NULL) @@ -8113,9 +8379,11 @@ ada_to_fixed_value_create (struct type *type0, CORE_ADDR address, struct value * ada_to_fixed_value (struct value *val) { - return ada_to_fixed_value_create (value_type (val), - value_address (val), - val); + val = unwrap_value (val); + val = ada_to_fixed_value_create (value_type (val), + value_address (val), + val); + return val; } @@ -8168,7 +8436,7 @@ pos_atr (struct value *arg) for (i = 0; i < TYPE_NFIELDS (type); i += 1) { - if (v == TYPE_FIELD_BITPOS (type, i)) + if (v == TYPE_FIELD_ENUMVAL (type, i)) return i; } error (_("enumeration value is invalid: can't find 'POS")); @@ -8199,7 +8467,7 @@ value_val_atr (struct type *type, struct value *arg) if (pos < 0 || pos >= TYPE_NFIELDS (type)) error (_("argument to 'VAL out of range")); - return value_from_longest (type, TYPE_FIELD_BITPOS (type, pos)); + return value_from_longest (type, TYPE_FIELD_ENUMVAL (type, pos)); } else return value_from_longest (type, value_as_long (arg)); @@ -8508,6 +8776,72 @@ cast_from_fixed (struct type *type, struct value *arg) return value_from_double (type, val); } +/* Given two array types T1 and T2, return nonzero iff both arrays + contain the same number of elements. */ + +static int +ada_same_array_size_p (struct type *t1, struct type *t2) +{ + LONGEST lo1, hi1, lo2, hi2; + + /* Get the array bounds in order to verify that the size of + the two arrays match. */ + if (!get_array_bounds (t1, &lo1, &hi1) + || !get_array_bounds (t2, &lo2, &hi2)) + error (_("unable to determine array bounds")); + + /* To make things easier for size comparison, normalize a bit + the case of empty arrays by making sure that the difference + between upper bound and lower bound is always -1. */ + if (lo1 > hi1) + hi1 = lo1 - 1; + if (lo2 > hi2) + hi2 = lo2 - 1; + + return (hi1 - lo1 == hi2 - lo2); +} + +/* Assuming that VAL is an array of integrals, and TYPE represents + an array with the same number of elements, but with wider integral + elements, return an array "casted" to TYPE. In practice, this + means that the returned array is built by casting each element + of the original array into TYPE's (wider) element type. */ + +static struct value * +ada_promote_array_of_integrals (struct type *type, struct value *val) +{ + struct type *elt_type = TYPE_TARGET_TYPE (type); + LONGEST lo, hi; + struct value *res; + LONGEST i; + + /* Verify that both val and type are arrays of scalars, and + that the size of val's elements is smaller than the size + of type's element. */ + gdb_assert (TYPE_CODE (type) == TYPE_CODE_ARRAY); + gdb_assert (is_integral_type (TYPE_TARGET_TYPE (type))); + gdb_assert (TYPE_CODE (value_type (val)) == TYPE_CODE_ARRAY); + gdb_assert (is_integral_type (TYPE_TARGET_TYPE (value_type (val)))); + gdb_assert (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) + > TYPE_LENGTH (TYPE_TARGET_TYPE (value_type (val)))); + + if (!get_array_bounds (type, &lo, &hi)) + error (_("unable to determine array bounds")); + + res = allocate_value (type); + + /* Promote each array element. */ + for (i = 0; i < hi - lo + 1; i++) + { + struct value *elt = value_cast (elt_type, value_subscript (val, lo + i)); + + memcpy (value_contents_writeable (res) + (i * TYPE_LENGTH (elt_type)), + value_contents_all (elt), TYPE_LENGTH (elt_type)); + } + + return res; +} + /* Coerce VAL as necessary for assignment to an lval of type TYPE, and return the converted value. */ @@ -8532,9 +8866,21 @@ coerce_for_assign (struct type *type, struct value *val) if (TYPE_CODE (type2) == TYPE_CODE_ARRAY && TYPE_CODE (type) == TYPE_CODE_ARRAY) { - if (TYPE_LENGTH (type2) != TYPE_LENGTH (type) - || TYPE_LENGTH (TYPE_TARGET_TYPE (type2)) - != TYPE_LENGTH (TYPE_TARGET_TYPE (type2))) + if (!ada_same_array_size_p (type, type2)) + error (_("cannot assign arrays of different length")); + + if (is_integral_type (TYPE_TARGET_TYPE (type)) + && is_integral_type (TYPE_TARGET_TYPE (type2)) + && TYPE_LENGTH (TYPE_TARGET_TYPE (type2)) + < TYPE_LENGTH (TYPE_TARGET_TYPE (type))) + { + /* Allow implicit promotion of the array elements to + a wider type. */ + return ada_promote_array_of_integrals (type, val); + } + + if (TYPE_LENGTH (TYPE_TARGET_TYPE (type2)) + != TYPE_LENGTH (TYPE_TARGET_TYPE (type))) error (_("Incompatible types in assignment")); deprecated_set_value_type (val, type); } @@ -8677,7 +9023,7 @@ assign_component (struct value *container, struct value *lhs, LONGEST index, else { elt = ada_index_struct_field (index, lhs, 0, value_type (lhs)); - elt = ada_to_fixed_value (unwrap_value (elt)); + elt = ada_to_fixed_value (elt); } if (exp->elts[*pos].opcode == OP_AGGREGATE) @@ -8709,7 +9055,6 @@ assign_aggregate (struct value *container, int num_specs; LONGEST *indices; int max_indices, num_indices; - int is_array_aggregate; int i; *pos += 3; @@ -8734,13 +9079,11 @@ assign_aggregate (struct value *container, lhs_type = value_type (lhs); low_index = TYPE_ARRAY_LOWER_BOUND_VALUE (lhs_type); high_index = TYPE_ARRAY_UPPER_BOUND_VALUE (lhs_type); - is_array_aggregate = 1; } else if (TYPE_CODE (lhs_type) == TYPE_CODE_STRUCT) { low_index = 0; high_index = num_visible_fields (lhs_type) - 1; - is_array_aggregate = 0; } else error (_("Left-hand side must be array or record.")); @@ -8851,7 +9194,7 @@ aggregate_assign_from_choices (struct value *container, else { int ind; - char *name; + const char *name; switch (op) { @@ -9253,7 +9596,9 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp, default: *pos -= 1; arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside); - arg1 = unwrap_value (arg1); + + if (noside == EVAL_NORMAL) + arg1 = unwrap_value (arg1); /* If evaluating an OP_DOUBLE and an EXPECT_TYPE was provided, then we need to perform the conversion manually, because @@ -9490,19 +9835,31 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp, a fixed type would result in the loss of that type name, thus preventing us from printing the name of the ancestor type in the type description. */ - struct type *actual_type; - arg1 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_NORMAL); - actual_type = type_from_tag (ada_value_tag (arg1)); - if (actual_type == NULL) - /* If, for some reason, we were unable to determine - the actual type from the tag, then use the static - approximation that we just computed as a fallback. - This can happen if the debugging information is - incomplete, for instance. */ - actual_type = type; - - return value_zero (actual_type, not_lval); + + if (TYPE_CODE (type) != TYPE_CODE_REF) + { + struct type *actual_type; + + actual_type = type_from_tag (ada_value_tag (arg1)); + if (actual_type == NULL) + /* If, for some reason, we were unable to determine + the actual type from the tag, then use the static + approximation that we just computed as a fallback. + This can happen if the debugging information is + incomplete, for instance. */ + actual_type = type; + return value_zero (actual_type, not_lval); + } + else + { + /* In the case of a ref, ada_coerce_ref takes care + of determining the actual type. But the evaluation + should return a ref as it should be valid to ask + for its address; so rebuild a ref after coerce. */ + arg1 = ada_coerce_ref (arg1); + return value_ref (arg1); + } } *pos += 4; @@ -9514,7 +9871,6 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp, else { arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside); - arg1 = unwrap_value (arg1); return ada_to_fixed_value (arg1); } @@ -9588,8 +9944,25 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp, { case TYPE_CODE_FUNC: if (noside == EVAL_AVOID_SIDE_EFFECTS) - return allocate_value (TYPE_TARGET_TYPE (type)); + { + struct type *rtype = TYPE_TARGET_TYPE (type); + + if (TYPE_GNU_IFUNC (type)) + return allocate_value (TYPE_TARGET_TYPE (rtype)); + return allocate_value (rtype); + } return call_function_by_hand (argvec[0], nargs, argvec + 1); + case TYPE_CODE_INTERNAL_FUNCTION: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + /* We don't know anything about what the internal + function might return, but we have to return + something. */ + return value_zero (builtin_type (exp->gdbarch)->builtin_int, + not_lval); + else + return call_internal_function (exp->gdbarch, exp->language_defn, + argvec[0], nargs, argvec + 1); + case TYPE_CODE_STRUCT: { int arity; @@ -9860,7 +10233,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp, else if (discrete_type_p (type_arg)) { struct type *range_type; - char *name = ada_type_name (type_arg); + const char *name = ada_type_name (type_arg); range_type = NULL; if (name != NULL && TYPE_CODE (type_arg) != TYPE_CODE_ENUM) @@ -10392,7 +10765,7 @@ get_int_var_value (char *name, int *flag) static struct type * to_fixed_range_type (struct type *raw_type, struct value *dval) { - char *name; + const char *name; struct type *base_type; char *subtype_info; @@ -10508,37 +10881,6 @@ ada_is_modular_type (struct type *type) && TYPE_UNSIGNED (subranged_type)); } -/* Try to determine the lower and upper bounds of the given modular type - using the type name only. Return non-zero and set L and U as the lower - and upper bounds (respectively) if successful. */ - -int -ada_modulus_from_name (struct type *type, ULONGEST *modulus) -{ - char *name = ada_type_name (type); - char *suffix; - int k; - LONGEST U; - - if (name == NULL) - return 0; - - /* Discrete type bounds are encoded using an __XD suffix. In our case, - we are looking for static bounds, which means an __XDLU suffix. - Moreover, we know that the lower bound of modular types is always - zero, so the actual suffix should start with "__XDLU_0__", and - then be followed by the upper bound value. */ - suffix = strstr (name, "__XDLU_0__"); - if (suffix == NULL) - return 0; - k = 10; - if (!ada_scan_number (suffix, k, &U, NULL)) - return 0; - - *modulus = (ULONGEST) U + 1; - return 1; -} - /* Assuming ada_is_modular_type (TYPE), the modulus of TYPE. */ ULONGEST @@ -10706,7 +11048,6 @@ static void ada_exception_support_info_sniffer (void) { struct ada_inferior_data *data = get_ada_inferior_data (current_inferior ()); - struct symbol *sym; /* If the exception info is already known, then no need to recompute it. */ if (data->exception_info != NULL) @@ -10762,9 +11103,10 @@ static int is_known_support_routine (struct frame_info *frame) { struct symtab_and_line sal; - char *func_name; + const char *func_name; enum language func_lang; int i; + const char *fullname; /* If this code does not have any debugging information (no symtab), This cannot be any user code. */ @@ -10779,7 +11121,8 @@ is_known_support_routine (struct frame_info *frame) for the user. This should also take care of case such as VxWorks where the kernel has some debugging info provided for a few units. */ - if (symtab_to_fullname (sal.symtab) == NULL) + fullname = symtab_to_fullname (sal.symtab); + if (access (fullname, R_OK) != 0) return 1; /* Check the unit filename againt the Ada runtime file naming. @@ -10790,7 +11133,7 @@ is_known_support_routine (struct frame_info *frame) for (i = 0; known_runtime_file_name_patterns[i] != NULL; i += 1) { re_comp (known_runtime_file_name_patterns[i]); - if (re_exec (sal.symtab->filename)) + if (re_exec (lbasename (sal.symtab->filename))) return 1; if (sal.symtab->objfile != NULL && re_exec (sal.symtab->objfile->name)) @@ -10865,7 +11208,7 @@ ada_unhandled_exception_name_addr_from_raise (void) while (fi != NULL) { - char *func_name; + const char *func_name; enum language func_lang; find_frame_funname (fi, &func_name, &func_lang, NULL); @@ -10925,7 +11268,7 @@ static CORE_ADDR ada_exception_name_addr (enum exception_catchpoint_kind ex, struct breakpoint *b) { - struct gdb_exception e; + volatile struct gdb_exception e; CORE_ADDR result = 0; TRY_CATCH (e, RETURN_MASK_ERROR) @@ -11041,12 +11384,13 @@ create_excep_cond_exprs (struct ada_catchpoint *c) if (!bl->shlib_disabled) { volatile struct gdb_exception e; - char *s; + const char *s; s = cond_string; TRY_CATCH (e, RETURN_MASK_ERROR) { - exp = parse_exp_1 (&s, block_for_pc (bl->address), 0); + exp = parse_exp_1 (&s, bl->address, + block_for_pc (bl->address), 0); } if (e.reason < 0) warning (_("failed to reevaluate internal exception condition " @@ -11472,7 +11816,7 @@ allocate_location_catch_assert (struct breakpoint *self) static void re_set_catch_assert (struct breakpoint *b) { - return re_set_exception (ex_catch_assert, b); + re_set_exception (ex_catch_assert, b); } static void @@ -11520,19 +11864,13 @@ ada_get_next_arg (char **argsp) char *end; char *result; - /* Skip any leading white space. */ - - while (isspace (*args)) - args++; - + args = skip_spaces (args); if (args[0] == '\0') return NULL; /* No more arguments. */ /* Find the end of the current argument. */ - end = args; - while (*end != '\0' && !isspace (*end)) - end++; + end = skip_to_space (args); /* Adjust ARGSP to point to the start of the next argument. */ @@ -11550,25 +11888,53 @@ ada_get_next_arg (char **argsp) /* Split the arguments specified in a "catch exception" command. Set EX to the appropriate catchpoint type. Set EXCEP_STRING to the name of the specific exception if - specified by the user. */ + specified by the user. + If a condition is found at the end of the arguments, the condition + expression is stored in COND_STRING (memory must be deallocated + after use). Otherwise COND_STRING is set to NULL. */ static void catch_ada_exception_command_split (char *args, enum exception_catchpoint_kind *ex, - char **excep_string) + char **excep_string, + char **cond_string) { struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); char *exception_name; + char *cond = NULL; exception_name = ada_get_next_arg (&args); + if (exception_name != NULL && strcmp (exception_name, "if") == 0) + { + /* This is not an exception name; this is the start of a condition + expression for a catchpoint on all exceptions. So, "un-get" + this token, and set exception_name to NULL. */ + xfree (exception_name); + exception_name = NULL; + args -= 2; + } make_cleanup (xfree, exception_name); + /* Check to see if we have a condition. */ + + args = skip_spaces (args); + if (strncmp (args, "if", 2) == 0 + && (isspace (args[2]) || args[2] == '\0')) + { + args += 2; + args = skip_spaces (args); + + if (args[0] == '\0') + error (_("Condition missing after `if' keyword")); + cond = xstrdup (args); + make_cleanup (xfree, cond); + + args += strlen (args); + } + /* Check that we do not have any more arguments. Anything else is unexpected. */ - while (isspace (*args)) - args++; - if (args[0] != '\0') error (_("Junk at end of expression")); @@ -11592,6 +11958,7 @@ catch_ada_exception_command_split (char *args, *ex = ex_catch_exception; *excep_string = exception_name; } + *cond_string = cond; } /* Return the name of the symbol on which we should break in order to @@ -11735,17 +12102,22 @@ ada_exception_sal (enum exception_catchpoint_kind ex, char *excep_string, If the user asked the catchpoint to catch only a specific exception, then save the exception name in ADDR_STRING. + If the user provided a condition, then set COND_STRING to + that condition expression (the memory must be deallocated + after use). Otherwise, set COND_STRING to NULL. + See ada_exception_sal for a description of all the remaining function arguments of this function. */ static struct symtab_and_line ada_decode_exception_location (char *args, char **addr_string, char **excep_string, + char **cond_string, const struct breakpoint_ops **ops) { enum exception_catchpoint_kind ex; - catch_ada_exception_command_split (args, &ex, excep_string); + catch_ada_exception_command_split (args, &ex, excep_string, cond_string); return ada_exception_sal (ex, *excep_string, addr_string, ops); } @@ -11756,6 +12128,7 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch, struct symtab_and_line sal, char *addr_string, char *excep_string, + char *cond_string, const struct breakpoint_ops *ops, int tempflag, int from_tty) @@ -11767,6 +12140,8 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch, ops, tempflag, from_tty); c->excep_string = excep_string; create_excep_cond_exprs (c); + if (cond_string != NULL) + set_breakpoint_condition (&c->base, cond_string, from_tty); install_breakpoint (0, &c->base, 1); } @@ -11781,31 +12156,54 @@ catch_ada_exception_command (char *arg, int from_tty, struct symtab_and_line sal; char *addr_string = NULL; char *excep_string = NULL; + char *cond_string = NULL; const struct breakpoint_ops *ops = NULL; tempflag = get_cmd_context (command) == CATCH_TEMPORARY; if (!arg) arg = ""; - sal = ada_decode_exception_location (arg, &addr_string, &excep_string, &ops); + sal = ada_decode_exception_location (arg, &addr_string, &excep_string, + &cond_string, &ops); create_ada_exception_catchpoint (gdbarch, sal, addr_string, - excep_string, ops, tempflag, from_tty); + excep_string, cond_string, ops, + tempflag, from_tty); } +/* Assuming that ARGS contains the arguments of a "catch assert" + command, parse those arguments and return a symtab_and_line object + for a failed assertion catchpoint. + + Set ADDR_STRING to the name of the function where the real + breakpoint that implements the catchpoint is set. + + If ARGS contains a condition, set COND_STRING to that condition + (the memory needs to be deallocated after use). Otherwise, set + COND_STRING to NULL. */ + static struct symtab_and_line ada_decode_assert_location (char *args, char **addr_string, + char **cond_string, const struct breakpoint_ops **ops) { - /* Check that no argument where provided at the end of the command. */ + args = skip_spaces (args); - if (args != NULL) + /* Check whether a condition was provided. */ + if (strncmp (args, "if", 2) == 0 + && (isspace (args[2]) || args[2] == '\0')) { - while (isspace (*args)) - args++; - if (*args != '\0') - error (_("Junk at end of arguments.")); + args += 2; + args = skip_spaces (args); + if (args[0] == '\0') + error (_("condition missing after `if' keyword")); + *cond_string = xstrdup (args); } + /* Otherwise, there should be no other argument at the end of + the command. */ + else if (args[0] != '\0') + error (_("Junk at end of arguments.")); + return ada_exception_sal (ex_catch_assert, NULL, addr_string, ops); } @@ -11819,15 +12217,17 @@ catch_assert_command (char *arg, int from_tty, int tempflag; struct symtab_and_line sal; char *addr_string = NULL; + char *cond_string = NULL; const struct breakpoint_ops *ops = NULL; tempflag = get_cmd_context (command) == CATCH_TEMPORARY; if (!arg) arg = ""; - sal = ada_decode_assert_location (arg, &addr_string, &ops); + sal = ada_decode_assert_location (arg, &addr_string, &cond_string, &ops); create_ada_exception_catchpoint (gdbarch, sal, addr_string, - NULL, ops, tempflag, from_tty); + NULL, cond_string, ops, tempflag, + from_tty); } /* Operators */ /* Information about operators given special treatment in functions @@ -12106,7 +12506,8 @@ ada_print_subexp (struct expression *exp, int *pos, if (exp->elts[*pos].opcode == OP_TYPE) { if (TYPE_CODE (exp->elts[*pos + 1].type) != TYPE_CODE_VOID) - LA_PRINT_TYPE (exp->elts[*pos + 1].type, "", stream, 0, 0); + LA_PRINT_TYPE (exp->elts[*pos + 1].type, "", stream, 0, 0, + &type_print_raw_options); *pos += 3; } else @@ -12136,7 +12537,8 @@ ada_print_subexp (struct expression *exp, int *pos, /* XXX: sprint_subexp */ print_subexp (exp, pos, stream, PREC_SUFFIX); fputs_filtered (" in ", stream); - LA_PRINT_TYPE (exp->elts[pc + 1].type, "", stream, 1, 0); + LA_PRINT_TYPE (exp->elts[pc + 1].type, "", stream, 1, 0, + &type_print_raw_options); return; case OP_DISCRETE_RANGE: @@ -12310,11 +12712,44 @@ static const struct exp_descriptor ada_exp_descriptor = { ada_evaluate_subexp }; +/* Implement the "la_get_symbol_name_cmp" language_defn method + for Ada. */ + +static symbol_name_cmp_ftype +ada_get_symbol_name_cmp (const char *lookup_name) +{ + if (should_use_wild_match (lookup_name)) + return wild_match; + else + return compare_names; +} + +/* Implement the "la_read_var_value" language_defn method for Ada. */ + +static struct value * +ada_read_var_value (struct symbol *var, struct frame_info *frame) +{ + struct block *frame_block = NULL; + struct symbol *renaming_sym = NULL; + + /* The only case where default_read_var_value is not sufficient + is when VAR is a renaming... */ + if (frame) + frame_block = get_frame_block (frame, NULL); + if (frame_block) + renaming_sym = ada_find_renaming_symbol (var, frame_block); + if (renaming_sym != NULL) + return ada_read_renaming_var_value (renaming_sym, frame_block); + + /* This is a typical case where we expect the default_read_var_value + function to work. */ + return default_read_var_value (var, frame); +} + const struct language_defn ada_language_defn = { "ada", /* Language name */ language_ada, range_check_off, - type_check_off, case_sensitive_on, /* Yes, Ada is case-insensitive, but that's not quite what this means. */ array_row_major, @@ -12330,6 +12765,7 @@ const struct language_defn ada_language_defn = { ada_print_typedef, /* Print a typedef using appropriate syntax */ ada_val_print, /* Print a value using appropriate syntax */ ada_value_print, /* Print a top-level value */ + ada_read_var_value, /* la_read_var_value */ NULL, /* Language specific skip_trampoline */ NULL, /* name_of_this */ ada_lookup_symbol_nonlocal, /* Looking up non-local symbols. */ @@ -12346,7 +12782,7 @@ const struct language_defn ada_language_defn = { ada_print_array_index, default_pass_by_reference, c_get_string, - compare_names, + ada_get_symbol_name_cmp, /* la_get_symbol_name_cmp */ ada_iterate_over_symbols, LANG_MAGIC }; @@ -12472,5 +12908,5 @@ With an argument, catch only exceptions with the given name."), /* Setup per-inferior data. */ observer_attach_inferior_exit (ada_inferior_exit); ada_inferior_data - = register_inferior_data_with_cleanup (ada_inferior_data_cleanup); + = register_inferior_data_with_cleanup (NULL, ada_inferior_data_cleanup); } diff --git a/contrib/gdb-7/gdb/ada-lang.h b/contrib/gdb-7/gdb/ada-lang.h index 9ab7b2dd17..55c0a8192a 100644 --- a/contrib/gdb-7/gdb/ada-lang.h +++ b/contrib/gdb-7/gdb/ada-lang.h @@ -1,7 +1,6 @@ /* Ada language support definitions for GDB, the GNU debugger. - Copyright (C) 1992, 1997-2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -23,6 +22,7 @@ struct frame_info; struct inferior; +struct type_print_options; #include "value.h" #include "gdbtypes.h" @@ -45,6 +45,7 @@ struct inferior; #if !defined (ADA_KNOWN_RUNTIME_FILE_NAME_PATTERNS) #define ADA_KNOWN_RUNTIME_FILE_NAME_PATTERNS \ + "^unwind-seh.c$", \ "^[agis]-.*\\.ad[bs]$", #endif @@ -80,11 +81,15 @@ struct ada_opname_map /* Defined in ada-lang.c */ extern const struct ada_opname_map ada_opname_table[]; -/* A tuple, (symbol, block), representing one instance of a - * symbol-lookup operation. */ -struct ada_symbol_info { - struct symbol* sym; - struct block* block; +/* A tuple representing one instance of a symbol-lookup operation. */ + +struct ada_symbol_info +{ + /* The symbol that was found. */ + struct symbol *sym; + + /* The block where the symbol was found. */ + const struct block *block; }; /* Denotes a type of renaming symbol (see ada_parse_renaming). */ @@ -159,18 +164,18 @@ extern void ada_error (char *); /* Defined in ada-exp.y */ /* Defined in ada-typeprint.c */ extern void ada_print_type (struct type *, const char *, struct ui_file *, int, - int); + int, const struct type_print_options *); extern void ada_print_typedef (struct type *type, struct symbol *new_symbol, struct ui_file *stream); -extern int ada_val_print (struct type *, const gdb_byte *, int, CORE_ADDR, - struct ui_file *, int, - const struct value *, - const struct value_print_options *); +extern void ada_val_print (struct type *, const gdb_byte *, int, CORE_ADDR, + struct ui_file *, int, + const struct value *, + const struct value_print_options *); -extern int ada_value_print (struct value *, struct ui_file *, - const struct value_print_options *); +extern void ada_value_print (struct value *, struct ui_file *, + const struct value_print_options *); /* Defined in ada-lang.c */ @@ -210,7 +215,11 @@ extern LONGEST ada_discrete_type_low_bound (struct type *); extern LONGEST ada_discrete_type_high_bound (struct type *); -extern char *ada_decode_symbol (const struct general_symbol_info*); +extern struct value *ada_get_decoded_value (struct value *value); + +extern struct type *ada_get_decoded_type (struct type *type); + +extern const char *ada_decode_symbol (const struct general_symbol_info *); extern const char *ada_decode (const char*); @@ -226,9 +235,9 @@ extern char *ada_fold_name (const char *); extern struct symbol *ada_lookup_symbol (const char *, const struct block *, domain_enum, int *); -extern struct symbol * -ada_lookup_encoded_symbol (const char *, const struct block *, - domain_enum namespace, struct block **); +extern void ada_lookup_encoded_symbol + (const char *name, const struct block *block, domain_enum namespace, + struct ada_symbol_info *symbol_info); extern struct minimal_symbol *ada_lookup_simple_minsym (const char *); @@ -267,6 +276,8 @@ extern struct value *ada_value_tag (struct value *); extern const char *ada_tag_name (struct value *); +extern struct value *ada_tag_value_at_base_address (struct value *obj); + extern int ada_is_parent_field (struct type *, int); extern int ada_is_wrapper_field (struct type *, int); @@ -321,19 +332,15 @@ extern struct type *ada_template_to_fixed_record_type_1 (struct type *type, extern int ada_name_prefix_len (const char *); -extern char *ada_type_name (struct type *); +extern const char *ada_type_name (struct type *); extern struct type *ada_find_parallel_type (struct type *, const char *suffix); extern LONGEST get_int_var_value (char *, int *); -extern struct symbol *ada_find_any_symbol (const char *name); - -extern struct type *ada_find_any_type (const char *name); - -extern struct symbol *ada_find_renaming_symbol (const char *name, - struct block *block); +extern struct symbol *ada_find_renaming_symbol (struct symbol *name_sym, + const struct block *block); extern int ada_prefer_type (struct type *, struct type *); diff --git a/contrib/gdb-7/gdb/ada-lex.c b/contrib/gdb-7/gdb/ada-lex.c index 92cd92cf65..1eaadb6522 100644 --- a/contrib/gdb-7/gdb/ada-lex.c +++ b/contrib/gdb-7/gdb/ada-lex.c @@ -1,68 +1,113 @@ #line 2 "ada-lex.c" -/* A lexical scanner generated by flex */ -/* Scanner skeleton version: - * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ - */ +#line 4 "ada-lex.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ #include -#include +#include +#include +#include +/* end standard C headers. */ -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) #endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) #endif +#endif /* ! FLEXINT_H */ #ifdef __cplusplus -#include - -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS - /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ -#if __STDC__ +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) -#define YY_USE_PROTOS #define YY_USE_CONST -#endif /* __STDC__ */ +#endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include -#include -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#endif - /* Returned upon end-of-file. */ #define YY_NULL 0 @@ -77,71 +122,70 @@ * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ -#define BEGIN yy_start = 1 + 2 * +#define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ -#define YY_START ((yy_start - 1) / 2) +#define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) +#define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ +#ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif extern int yyleng; + extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) -#define unput(c) yyunput( c, yytext_ptr ) - -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ -typedef unsigned int yy_size_t; +#define unput(c) yyunput( c, (yytext_ptr) ) +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; @@ -178,12 +222,16 @@ struct yy_buffer_state */ int yy_at_bol; + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; + #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process @@ -197,28 +245,38 @@ struct yy_buffer_state * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ -static YY_BUFFER_STATE yy_current_buffer = 0; +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". + * + * Returns the top of the stack, or NULL. */ -#define YY_CURRENT_BUFFER yy_current_buffer +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; - static int yy_n_chars; /* number of characters read into yy_ch_buf */ - - int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; -static int yy_init = 1; /* whether we need to initialize */ +static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches @@ -226,92 +284,119 @@ static int yy_start = 0; /* start state number */ */ static int yy_did_buffer_switch_on_eof; -void yyrestart YY_PROTO(( FILE *input_file )); +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yyxrealloc YY_PROTO(( void *, yy_size_t )); -static void yy_flex_free YY_PROTO(( void * )); +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); + +void *yyalloc (yy_size_t ); +void *yyxrealloc (void *,yy_size_t ); +void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ typedef unsigned char YY_CHAR; + FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + extern char *yytext; #define yytext_ptr yytext -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ - yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; + (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 54 -#define YY_END_OF_BUFFER 55 -static yyconst short int yy_accept[196] = +#define YY_NUM_RULES 55 +#define YY_END_OF_BUFFER 56 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[207] = { 0, - 0, 0, 0, 0, 55, 53, 1, 1, 15, 52, - 42, 53, 44, 45, 42, 43, 42, 42, 42, 4, - 4, 42, 42, 42, 42, 51, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 41, 0, 14, - 0, 52, 0, 0, 0, 0, 0, 0, 0, 36, - 2, 0, 35, 0, 47, 47, 38, 0, 0, 4, - 0, 0, 50, 37, 39, 0, 34, 40, 0, 0, - 48, 0, 48, 48, 48, 48, 48, 16, 21, 48, - 48, 48, 48, 26, 48, 48, 48, 48, 48, 48, - 0, 14, 0, 12, 12, 0, 33, 2, 0, 47, - - 47, 0, 9, 0, 3, 7, 0, 48, 0, 0, - 0, 48, 18, 19, 48, 48, 22, 23, 24, 48, - 48, 28, 48, 48, 48, 48, 30, 0, 0, 0, - 0, 0, 0, 47, 46, 6, 0, 0, 9, 0, + 0, 0, 0, 0, 56, 54, 1, 1, 15, 53, + 43, 54, 45, 46, 43, 44, 43, 43, 43, 4, + 4, 43, 43, 43, 43, 52, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 42, 0, 14, + 0, 53, 0, 0, 0, 0, 0, 0, 0, 37, + 2, 0, 36, 0, 48, 48, 39, 0, 0, 4, + 0, 0, 51, 38, 40, 0, 35, 41, 0, 0, + 49, 0, 49, 49, 49, 49, 49, 16, 22, 49, + 49, 49, 49, 27, 49, 49, 49, 49, 49, 49, + 0, 14, 0, 12, 12, 34, 0, 2, 0, 48, + + 48, 0, 9, 0, 3, 7, 0, 49, 0, 0, + 0, 49, 19, 20, 49, 49, 23, 24, 25, 49, + 49, 29, 49, 49, 49, 49, 31, 0, 0, 0, + 0, 0, 0, 48, 47, 6, 0, 0, 9, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 48, 20, 48, 25, 48, 17, 29, - 48, 31, 0, 49, 0, 0, 0, 0, 48, 0, - 0, 0, 0, 0, 0, 0, 32, 48, 48, 0, - 0, 5, 11, 0, 8, 27, 0, 5, 0, 8, - 13, 0, 10, 10, 0 + 0, 0, 0, 49, 21, 49, 26, 49, 17, 30, + 49, 32, 0, 50, 0, 0, 0, 0, 49, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 49, 49, + 0, 0, 5, 11, 0, 8, 0, 0, 0, 0, + 0, 0, 28, 49, 0, 5, 0, 8, 0, 0, + 13, 0, 18, 10, 10, 0 } ; -static yyconst int yy_ec[256] = +static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -319,14 +404,14 @@ static yyconst int yy_ec[256] = 1, 4, 5, 6, 7, 8, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 22, 23, - 24, 25, 5, 26, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 36, 39, 40, 41, 42, 43, 36, - 36, 44, 45, 46, 47, 36, 48, 49, 36, 36, - 27, 5, 28, 5, 29, 5, 30, 31, 32, 33, - - 34, 35, 36, 37, 38, 36, 39, 40, 41, 42, - 43, 36, 36, 44, 45, 46, 47, 36, 48, 49, - 36, 36, 26, 22, 26, 5, 1, 1, 1, 1, + 24, 25, 5, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 33, 36, 37, 38, 39, 40, 33, + 33, 41, 42, 43, 44, 33, 45, 46, 33, 33, + 47, 5, 48, 5, 49, 5, 50, 51, 29, 52, + + 53, 54, 33, 55, 56, 33, 57, 58, 59, 60, + 61, 33, 33, 62, 63, 64, 65, 33, 66, 67, + 33, 33, 26, 22, 26, 5, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -343,260 +428,379 @@ static yyconst int yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst int yy_meta[50] = +static yyconst flex_int32_t yy_meta[68] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 9, 5, 5, 5, 5, 5, 5, 10, 5, 11, 11, - 5, 5, 12, 13, 14, 5, 5, 5, 15, 16, - 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17 + 5, 5, 12, 13, 14, 5, 15, 15, 15, 15, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 5, 5, 17, 15, + 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16 } ; -static yyconst short int yy_base[217] = +static yyconst flex_int16_t yy_base[229] = { 0, - 0, 0, 622, 615, 620, 759, 759, 759, 44, 0, - 759, 71, 759, 759, 606, 759, 601, 119, 591, 118, - 124, 30, 590, 588, 588, 759, 53, 152, 22, 97, - 98, 103, 117, 119, 27, 140, 137, 194, 151, 759, - 160, 0, 242, 601, 594, 593, 592, 120, 282, 759, - 0, 330, 759, 0, 0, 560, 759, 0, 40, 329, - 171, 0, 759, 759, 759, 574, 759, 759, 171, 245, - 759, 336, 150, 219, 223, 226, 227, 162, 228, 262, - 263, 310, 266, 265, 313, 268, 312, 330, 320, 334, - 572, 569, 366, 377, 759, 380, 547, 0, 530, 0, - - 501, 169, 363, 46, 365, 0, 503, 386, 402, 417, - 0, 417, 335, 344, 412, 387, 360, 386, 406, 413, - 431, 407, 425, 408, 437, 438, 421, 518, 0, 472, - 497, 475, 474, 759, 0, 456, 0, 246, 458, 284, - 462, 451, 403, 464, 477, 478, 454, 408, 402, 392, - 390, 364, 376, 509, 455, 483, 458, 485, 473, 489, - 491, 492, 367, 759, 387, 516, 366, 48, 535, 326, - 312, 270, 220, 219, 207, 164, 501, 509, 511, 144, - 282, 527, 98, 117, 529, 519, 42, 540, 321, 543, - 562, 403, 548, 551, 759, 580, 590, 606, 611, 627, - - 644, 647, 654, 487, 562, 661, 677, 689, 695, 706, - 708, 724, 563, 565, 731, 742 + 0, 0, 649, 638, 646, 1252, 1252, 1252, 62, 0, + 1252, 109, 1252, 1252, 623, 1252, 619, 175, 606, 174, + 180, 48, 604, 592, 590, 1252, 204, 71, 214, 186, + 235, 244, 304, 256, 39, 368, 40, 430, 179, 1252, + 195, 0, 602, 595, 592, 585, 574, 497, 72, 1252, + 0, 273, 1252, 0, 39, 0, 1252, 0, 66, 262, + 75, 0, 1252, 1252, 1252, 557, 1252, 1252, 284, 300, + 1252, 322, 329, 349, 358, 377, 339, 396, 412, 563, + 566, 575, 584, 587, 569, 596, 623, 616, 576, 617, + 571, 568, 334, 380, 1252, 562, 677, 0, 403, 0, + + 40, 89, 642, 71, 163, 0, 401, 672, 401, 723, + 0, 708, 741, 750, 637, 776, 785, 794, 797, 806, + 775, 827, 831, 843, 818, 819, 883, 415, 0, 712, + 399, 885, 352, 1252, 0, 191, 0, 202, 772, 170, + 243, 334, 222, 244, 247, 259, 766, 47, 209, 216, + 203, 251, 302, 892, 916, 890, 942, 715, 946, 958, + 930, 974, 274, 1252, 93, 344, 278, 310, 979, 256, + 264, 337, 270, 274, 352, 355, 215, 984, 995, 1000, + 299, 354, 589, 355, 223, 603, 209, 204, 198, 189, + 174, 101, 1004, 1016, 92, 634, 411, 644, 872, 1021, + + 717, 373, 1252, 793, 832, 1252, 1055, 1065, 1081, 1086, + 1102, 1119, 1136, 1139, 1146, 339, 560, 1153, 1169, 1181, + 1186, 1197, 1200, 1216, 634, 645, 1223, 1234 } ; -static yyconst short int yy_def[217] = +static yyconst flex_int16_t yy_def[229] = { 0, - 195, 1, 1, 1, 195, 195, 195, 195, 196, 197, - 195, 195, 195, 195, 195, 195, 195, 198, 195, 195, - 195, 195, 199, 195, 195, 195, 200, 200, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 195, 196, 195, - 196, 197, 38, 38, 38, 43, 195, 43, 43, 195, - 201, 198, 195, 202, 203, 203, 195, 204, 195, 195, - 195, 205, 195, 195, 195, 206, 195, 195, 195, 195, - 195, 207, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 49, 208, 195, 195, 195, 43, 49, 201, 209, 203, - - 203, 210, 195, 195, 195, 205, 206, 195, 207, 195, - 211, 212, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 195, 213, 195, - 195, 43, 209, 195, 203, 195, 214, 210, 195, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 215, 212, 28, 28, 28, 28, 28, 28, - 28, 28, 195, 195, 43, 195, 216, 195, 195, 195, - 195, 195, 195, 195, 195, 215, 28, 28, 28, 43, - 195, 195, 195, 216, 195, 28, 43, 195, 195, 195, - 195, 195, 195, 195, 0, 195, 195, 195, 195, 195, - - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 195, 195, 195, 195 + 206, 1, 1, 1, 206, 206, 206, 206, 207, 208, + 206, 206, 206, 206, 206, 206, 206, 209, 206, 206, + 206, 206, 210, 206, 206, 206, 211, 211, 211, 211, + 211, 211, 211, 211, 33, 211, 33, 206, 207, 206, + 207, 208, 212, 38, 38, 212, 206, 206, 212, 206, + 213, 209, 206, 214, 215, 215, 206, 216, 206, 206, + 206, 217, 206, 206, 206, 218, 206, 206, 206, 206, + 206, 219, 211, 211, 211, 211, 211, 211, 211, 211, + 211, 211, 211, 211, 36, 211, 211, 36, 33, 36, + 48, 220, 206, 206, 206, 48, 212, 213, 221, 215, + + 215, 222, 206, 206, 206, 217, 218, 206, 219, 206, + 223, 224, 211, 211, 33, 211, 211, 211, 211, 211, + 33, 211, 211, 211, 33, 33, 211, 206, 225, 206, + 206, 97, 221, 206, 215, 206, 226, 222, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 227, 224, 211, 33, 211, 36, 211, 211, + 36, 211, 206, 206, 212, 206, 228, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 227, 211, 211, 211, + 212, 206, 206, 206, 228, 206, 206, 206, 206, 206, + 206, 206, 211, 211, 212, 206, 206, 206, 206, 206, + + 206, 206, 206, 206, 206, 0, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206 } ; -static yyconst short int yy_nxt[809] = +static yyconst flex_int16_t yy_nxt[1320] = { 0, 6, 7, 8, 7, 6, 9, 6, 10, 11, 12, 13, 14, 15, 11, 16, 17, 18, 19, 20, 21, - 22, 11, 23, 24, 25, 26, 11, 11, 27, 28, - 27, 27, 27, 29, 30, 27, 27, 31, 27, 27, - 32, 33, 34, 35, 27, 36, 27, 27, 37, 40, - 63, 191, 73, 64, 69, 69, 70, 73, 103, 103, - 86, 76, 71, 73, 105, 105, 185, 185, 73, 72, - 41, 43, 44, 44, 45, 46, 46, 46, 46, 46, - 47, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 48, 46, 46, - - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 52, 52, 52, 183, 58, 96, 77, 73, 73, 94, - 58, 189, 78, 73, 59, 53, 60, 60, 73, 79, - 59, 54, 60, 60, 73, 80, 60, 73, 56, 73, - 81, 61, 60, 69, 69, 70, 40, 61, 73, 82, - 73, 71, 84, 83, 85, 92, 62, 73, 72, 87, - 73, 187, 69, 69, 69, 136, 88, 41, 73, 90, - 73, 73, 74, 89, 104, 137, 41, 72, 169, 105, - 105, 73, 73, 75, 43, 44, 44, 44, 43, 43, - - 43, 43, 43, 73, 43, 43, 43, 43, 43, 43, + 22, 11, 23, 24, 25, 26, 27, 28, 28, 28, + 29, 30, 28, 28, 31, 28, 28, 32, 33, 34, + 35, 28, 36, 28, 28, 37, 11, 11, 28, 27, + 28, 28, 29, 30, 28, 31, 28, 28, 32, 33, + 34, 35, 28, 36, 28, 28, 37, 40, 63, 86, + 73, 64, 69, 69, 70, 101, 135, 97, 73, 90, + 71, 94, 73, 73, 103, 103, 172, 72, 104, 105, + 105, 86, 73, 105, 105, 136, 101, 135, 181, 73, + + 90, 201, 93, 73, 73, 137, 169, 172, 41, 43, + 44, 44, 45, 46, 46, 46, 46, 46, 47, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 49, 46, 46, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 52, 52, 52, 169, + 58, 141, 141, 168, 40, 168, 58, 69, 69, 70, + 59, 53, 60, 60, 169, 71, 59, 54, 60, 60, + + 92, 55, 72, 169, 61, 69, 69, 70, 136, 169, + 61, 141, 77, 71, 169, 69, 69, 70, 137, 62, + 72, 166, 60, 71, 55, 41, 61, 169, 60, 184, + 72, 74, 61, 175, 142, 77, 69, 69, 70, 169, + 62, 41, 75, 166, 71, 69, 69, 70, 173, 169, + 76, 72, 169, 71, 74, 175, 174, 69, 69, 70, + 72, 141, 141, 75, 169, 71, 78, 142, 58, 173, + 142, 76, 72, 79, 52, 52, 52, 174, 59, 169, + 60, 60, 142, 80, 184, 69, 69, 69, 78, 206, + 176, 141, 61, 188, 79, 54, 84, 187, 85, 55, + + 72, 69, 69, 70, 80, 69, 69, 70, 93, 71, + 60, 176, 190, 71, 61, 188, 72, 84, 187, 85, + 72, 39, 55, 109, 109, 109, 169, 110, 186, 186, + 69, 69, 70, 190, 81, 130, 130, 130, 71, 169, + 69, 69, 70, 82, 111, 72, 195, 83, 71, 102, + 69, 69, 70, 102, 131, 72, 81, 182, 71, 69, + 69, 70, 183, 183, 82, 72, 189, 71, 83, 69, + 69, 70, 183, 183, 72, 116, 134, 71, 69, 69, + 70, 130, 130, 130, 72, 197, 71, 114, 189, 191, + 113, 204, 204, 72, 87, 192, 116, 69, 69, 70, + + 131, 88, 109, 109, 109, 71, 110, 197, 89, 114, + 191, 113, 72, 69, 69, 70, 192, 87, 115, 164, + 163, 71, 88, 111, 202, 108, 202, 134, 72, 89, + 43, 44, 44, 44, 43, 43, 43, 43, 43, 115, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 91, 91, 91, 91, 91, 91, 91, + 43, 43, 43, 43, 43, 43, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 43, 43, 43, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, - 91, 91, 91, 43, 43, 43, 69, 69, 70, 73, - 142, 93, 136, 73, 71, 114, 73, 73, 73, 142, - 73, 72, 137, 113, 73, 142, 116, 73, 73, 73, - 115, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 91, 91, 91, 91, 91, 91, 91, 43, 43, 43, + + 43, 43, 43, 43, 43, 43, 94, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 43, 43, 43, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 69, 69, 70, 69, 69, 70, + 106, 93, 71, 128, 106, 71, 69, 69, 70, 72, + 93, 108, 72, 95, 71, 69, 69, 70, 69, 69, + 70, 72, 117, 71, 94, 73, 71, 69, 69, 70, + + 72, 94, 121, 72, 93, 71, 73, 196, 196, 73, + 118, 93, 72, 68, 117, 73, 67, 119, 73, 126, + 120, 198, 198, 121, 69, 69, 70, 65, 73, 57, + 73, 118, 71, 122, 51, 50, 73, 196, 119, 72, + 126, 120, 73, 73, 128, 206, 124, 38, 128, 73, + 73, 198, 196, 196, 122, 167, 125, 127, 38, 167, + 139, 139, 198, 198, 123, 73, 73, 155, 124, 206, + 73, 73, 140, 69, 69, 70, 73, 125, 127, 206, + 73, 71, 196, 206, 206, 123, 93, 206, 72, 155, + 139, 206, 198, 206, 140, 132, 132, 73, 206, 206, + + 206, 73, 206, 132, 132, 132, 132, 132, 132, 69, + 69, 70, 206, 130, 130, 130, 206, 71, 130, 130, + 130, 206, 206, 206, 72, 206, 132, 132, 132, 132, + 132, 142, 131, 206, 206, 143, 142, 131, 142, 206, + 144, 73, 69, 69, 70, 145, 142, 146, 73, 147, + 71, 69, 69, 70, 206, 179, 206, 72, 206, 71, + 148, 149, 150, 151, 73, 206, 72, 206, 152, 73, + 206, 206, 147, 206, 206, 206, 179, 69, 69, 70, + 206, 148, 149, 150, 151, 71, 69, 69, 70, 152, + 139, 139, 72, 170, 71, 69, 69, 70, 69, 69, + + 70, 72, 140, 71, 171, 158, 71, 69, 69, 70, + 72, 205, 205, 72, 73, 71, 170, 156, 73, 206, + 139, 206, 72, 206, 140, 171, 206, 158, 69, 69, + 70, 206, 69, 69, 70, 73, 71, 206, 156, 73, + 71, 205, 157, 72, 69, 69, 70, 72, 161, 162, + 205, 205, 71, 206, 206, 206, 206, 73, 73, 72, + 206, 73, 73, 157, 206, 206, 159, 206, 206, 206, + 161, 162, 206, 199, 199, 199, 206, 206, 73, 73, + 205, 160, 73, 73, 69, 69, 70, 159, 72, 206, + 203, 203, 71, 69, 69, 70, 206, 206, 206, 72, + + 206, 71, 160, 165, 165, 206, 206, 206, 72, 206, + 206, 165, 165, 165, 165, 165, 165, 69, 69, 70, + 178, 206, 206, 206, 206, 71, 206, 206, 206, 73, + 206, 206, 72, 73, 165, 165, 165, 165, 165, 206, + 206, 206, 178, 69, 69, 70, 206, 69, 69, 70, + 73, 71, 206, 206, 73, 71, 180, 206, 72, 69, + 69, 70, 72, 73, 206, 206, 206, 71, 206, 206, + 73, 206, 206, 206, 72, 69, 69, 70, 206, 180, + 69, 69, 70, 71, 73, 69, 69, 70, 71, 206, + 72, 73, 206, 71, 206, 72, 69, 69, 70, 206, + + 72, 69, 69, 70, 71, 69, 69, 70, 206, 71, + 206, 72, 206, 71, 206, 206, 72, 199, 199, 200, + 72, 206, 199, 199, 200, 71, 206, 206, 206, 194, + 71, 206, 72, 206, 206, 206, 193, 72, 206, 203, + 203, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 194, 206, 206, 206, 206, 206, 193, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 42, 206, 206, 42, 206, 206, 206, 42, + 42, 42, 56, 56, 56, 206, 206, 206, 206, 206, + 56, 206, 56, 206, 206, 56, 56, 56, 66, 206, + + 66, 66, 66, 73, 73, 73, 206, 206, 206, 206, + 73, 73, 73, 206, 206, 206, 73, 73, 73, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 94, 73, 73, 117, 73, 73, 168, 73, 168, - - 182, 182, 142, 73, 73, 120, 73, 73, 122, 73, - 118, 97, 97, 97, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, - 97, 52, 52, 52, 192, 58, 192, 109, 109, 109, - 73, 110, 73, 73, 142, 59, 195, 60, 60, 121, - 73, 73, 54, 73, 73, 119, 123, 60, 111, 56, - 73, 73, 61, 124, 73, 73, 126, 130, 130, 130, - 142, 73, 183, 125, 73, 73, 73, 127, 130, 130, - 130, 139, 139, 141, 141, 73, 131, 69, 69, 70, - 73, 139, 180, 141, 39, 71, 140, 131, 132, 132, - - 169, 73, 72, 109, 109, 109, 175, 110, 169, 132, - 132, 132, 132, 132, 132, 142, 73, 73, 69, 69, - 70, 193, 193, 174, 111, 142, 71, 73, 73, 143, - 142, 156, 142, 72, 144, 142, 73, 73, 73, 145, - 142, 146, 73, 73, 173, 155, 147, 73, 73, 160, - 172, 73, 157, 73, 73, 73, 169, 148, 149, 150, - 151, 73, 73, 159, 158, 152, 73, 73, 73, 169, - 161, 162, 73, 130, 130, 130, 139, 139, 73, 73, - 141, 141, 169, 169, 170, 73, 139, 142, 73, 166, - 141, 140, 131, 165, 165, 171, 73, 102, 134, 73, - - 142, 142, 102, 73, 165, 165, 165, 165, 165, 165, - 69, 69, 70, 73, 73, 73, 177, 164, 71, 73, - 179, 73, 73, 163, 73, 72, 73, 108, 178, 181, - 73, 73, 73, 73, 182, 182, 69, 69, 70, 73, - 135, 73, 73, 159, 71, 188, 188, 190, 190, 73, - 73, 72, 73, 186, 134, 188, 93, 190, 188, 188, - 73, 190, 190, 130, 130, 130, 194, 194, 188, 194, - 194, 190, 106, 128, 128, 167, 194, 106, 128, 194, - 167, 93, 131, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 42, 108, 101, - - 42, 95, 94, 94, 42, 42, 42, 55, 55, 55, - 93, 68, 67, 65, 57, 55, 51, 55, 50, 195, - 55, 55, 55, 66, 38, 66, 66, 66, 73, 73, - 73, 38, 195, 195, 195, 73, 73, 73, 195, 195, - 195, 73, 73, 73, 98, 98, 195, 98, 98, 98, + 43, 43, 43, 43, 43, 43, 98, 98, 206, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, - 98, 99, 99, 99, 100, 195, 195, 195, 100, 100, - 100, 107, 195, 195, 107, 107, 107, 107, 112, 112, - 112, 195, 112, 195, 195, 195, 195, 195, 112, 195, - 195, 112, 112, 112, 129, 195, 195, 195, 195, 129, - - 195, 195, 195, 195, 129, 133, 195, 195, 133, 133, - 133, 133, 138, 195, 195, 138, 138, 195, 195, 195, - 138, 138, 153, 153, 153, 154, 154, 154, 195, 195, - 195, 195, 154, 154, 154, 195, 195, 195, 154, 154, - 154, 176, 195, 195, 176, 176, 176, 176, 184, 195, - 195, 195, 184, 195, 195, 195, 184, 184, 5, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - - 195, 195, 195, 195, 195, 195, 195, 195 + 98, 98, 98, 99, 99, 99, 100, 206, 206, 206, + 100, 100, 100, 107, 206, 206, 107, 107, 107, 107, + 112, 112, 112, 206, 112, 206, 206, 206, 206, 206, + 112, 206, 206, 112, 112, 112, 129, 206, 206, 206, + 206, 129, 206, 206, 206, 129, 133, 206, 206, 133, + + 133, 133, 133, 138, 206, 206, 138, 138, 206, 206, + 206, 138, 206, 138, 153, 153, 153, 154, 154, 154, + 206, 206, 206, 206, 154, 154, 154, 206, 206, 206, + 154, 154, 154, 177, 206, 206, 177, 177, 177, 177, + 185, 206, 206, 206, 185, 206, 206, 206, 185, 206, + 185, 5, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206 } ; -static yyconst short int yy_chk[809] = +static yyconst flex_int16_t yy_chk[1320] = { 0, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, - 22, 187, 29, 22, 27, 27, 27, 35, 59, 59, - 35, 29, 27, 29, 104, 104, 168, 168, 35, 27, - 9, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 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, 1, 1, 9, 22, 35, + 37, 22, 28, 28, 28, 55, 101, 49, 35, 37, + 28, 49, 35, 37, 59, 59, 148, 28, 61, 104, + 104, 35, 37, 61, 61, 102, 55, 101, 165, 35, + + 37, 195, 165, 35, 37, 102, 192, 148, 9, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 18, 18, 18, 184, 20, 48, 30, 30, 31, 48, - 21, 183, 31, 32, 20, 18, 20, 20, 30, 31, - 21, 18, 21, 21, 32, 32, 20, 33, 18, 34, - 33, 20, 21, 28, 28, 28, 39, 21, 33, 33, - 34, 28, 34, 33, 34, 41, 20, 37, 28, 36, - 36, 180, 69, 69, 69, 102, 36, 39, 37, 37, - 73, 36, 28, 36, 61, 102, 41, 69, 176, 61, - 61, 73, 78, 28, 38, 38, 38, 38, 38, 38, - - 38, 38, 38, 78, 38, 38, 38, 38, 38, 38, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 18, 18, 18, 191, + 20, 105, 105, 140, 39, 140, 21, 30, 30, 30, + 20, 18, 20, 20, 190, 30, 21, 18, 21, 21, + + 41, 18, 30, 189, 20, 27, 27, 27, 138, 188, + 21, 105, 30, 27, 187, 29, 29, 29, 138, 20, + 27, 136, 20, 29, 18, 39, 20, 143, 21, 185, + 29, 27, 21, 151, 143, 30, 31, 31, 31, 177, + 20, 41, 27, 136, 31, 32, 32, 32, 149, 144, + 29, 31, 145, 32, 27, 151, 150, 34, 34, 34, + 32, 141, 141, 27, 146, 34, 31, 144, 60, 149, + 145, 29, 34, 31, 52, 52, 52, 150, 60, 174, + 60, 60, 146, 32, 167, 69, 69, 69, 31, 52, + 152, 141, 60, 171, 31, 52, 34, 170, 34, 52, + + 69, 70, 70, 70, 32, 33, 33, 33, 181, 70, + 60, 152, 173, 33, 60, 171, 70, 34, 170, 34, + 33, 163, 52, 72, 72, 72, 153, 72, 168, 168, + 73, 73, 73, 173, 33, 93, 93, 93, 73, 142, + 77, 77, 77, 33, 72, 73, 181, 33, 77, 216, + 74, 74, 74, 216, 93, 77, 33, 166, 74, 75, + 75, 75, 166, 166, 33, 74, 172, 75, 33, 36, + 36, 36, 182, 182, 75, 77, 133, 36, 76, 76, + 76, 94, 94, 94, 36, 184, 76, 75, 172, 175, + 74, 202, 202, 76, 36, 176, 77, 78, 78, 78, + + 94, 36, 109, 109, 109, 78, 109, 184, 36, 75, + 175, 74, 78, 79, 79, 79, 176, 36, 76, 131, + 128, 79, 36, 109, 197, 107, 197, 99, 79, 36, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 76, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 43, 43, 43, 70, 70, 70, 74, - 175, 43, 138, 75, 70, 75, 76, 77, 79, 174, - 74, 70, 138, 74, 75, 173, 77, 76, 77, 79, - 76, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 49, 80, 81, 80, 84, 83, 140, 86, 140, - - 181, 181, 172, 80, 81, 83, 84, 83, 86, 86, - 81, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 52, 52, 52, 189, 60, 189, 72, 72, 72, - 82, 72, 87, 85, 171, 60, 52, 60, 60, 85, - 89, 82, 52, 87, 85, 82, 87, 60, 72, 52, - 88, 89, 60, 88, 90, 113, 89, 93, 93, 93, - 170, 88, 167, 88, 114, 90, 113, 90, 94, 94, - 94, 103, 103, 105, 105, 114, 93, 108, 108, 108, - 117, 103, 165, 105, 163, 108, 103, 94, 96, 96, - - 153, 117, 108, 109, 109, 109, 152, 109, 143, 96, - 96, 96, 96, 96, 96, 143, 118, 116, 112, 112, - 112, 192, 192, 151, 109, 110, 112, 118, 116, 110, - 110, 116, 110, 112, 110, 150, 119, 122, 124, 110, - 110, 110, 115, 120, 149, 115, 110, 119, 122, 124, - 148, 127, 120, 115, 120, 123, 142, 110, 110, 110, - 110, 121, 127, 123, 121, 110, 123, 125, 126, 144, - 125, 126, 121, 130, 130, 130, 139, 139, 125, 126, - 141, 141, 145, 146, 147, 155, 139, 144, 157, 136, - 141, 139, 130, 132, 132, 147, 155, 204, 133, 157, - - 145, 146, 204, 159, 132, 132, 132, 132, 132, 132, - 154, 154, 154, 156, 159, 158, 156, 131, 154, 160, - 161, 161, 162, 128, 156, 154, 158, 107, 158, 166, - 160, 177, 161, 162, 166, 166, 169, 169, 169, 178, - 101, 179, 177, 179, 169, 182, 182, 185, 185, 186, - 178, 169, 179, 178, 99, 182, 97, 185, 188, 188, - 186, 190, 190, 191, 191, 191, 193, 193, 188, 194, - 194, 190, 205, 213, 92, 214, 193, 205, 213, 194, - 214, 91, 191, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 197, 66, 56, - - 197, 47, 46, 45, 197, 197, 197, 198, 198, 198, - 44, 25, 24, 23, 19, 198, 17, 198, 15, 5, - 198, 198, 198, 199, 4, 199, 199, 199, 200, 200, - 200, 3, 0, 0, 0, 200, 200, 200, 0, 0, - 0, 200, 200, 200, 201, 201, 0, 201, 201, 201, - 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, - 201, 202, 202, 202, 203, 0, 0, 0, 203, 203, - 203, 206, 0, 0, 206, 206, 206, 206, 207, 207, - 207, 0, 207, 0, 0, 0, 0, 0, 207, 0, - 0, 207, 207, 207, 208, 0, 0, 0, 0, 208, - - 0, 0, 0, 0, 208, 209, 0, 0, 209, 209, - 209, 209, 210, 0, 0, 210, 210, 0, 0, 0, - 210, 210, 211, 211, 211, 212, 212, 212, 0, 0, - 0, 0, 212, 212, 212, 0, 0, 0, 212, 212, - 212, 215, 0, 0, 215, 215, 215, 215, 216, 0, - 0, 0, 216, 0, 0, 0, 216, 216, 195, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - - 195, 195, 195, 195, 195, 195, 195, 195 + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 48, 48, 48, + + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 80, 80, 80, 81, 81, 81, + 217, 96, 80, 92, 217, 81, 82, 82, 82, 80, + 91, 66, 81, 47, 82, 83, 83, 83, 84, 84, + 84, 82, 80, 83, 46, 85, 84, 86, 86, 86, + + 83, 45, 85, 84, 44, 86, 89, 183, 183, 85, + 81, 43, 86, 25, 80, 89, 24, 82, 85, 89, + 83, 186, 186, 85, 87, 87, 87, 23, 89, 19, + 85, 81, 87, 86, 17, 15, 89, 183, 82, 87, + 89, 83, 88, 90, 225, 5, 88, 4, 225, 88, + 90, 186, 196, 196, 86, 226, 88, 90, 3, 226, + 103, 103, 198, 198, 87, 88, 90, 115, 88, 0, + 88, 90, 103, 108, 108, 108, 115, 88, 90, 0, + 115, 108, 196, 0, 0, 87, 97, 0, 108, 115, + 103, 0, 198, 0, 103, 97, 97, 115, 0, 0, + + 0, 115, 0, 97, 97, 97, 97, 97, 97, 112, + 112, 112, 0, 130, 130, 130, 0, 112, 201, 201, + 201, 0, 0, 0, 112, 0, 97, 97, 97, 97, + 97, 110, 130, 0, 0, 110, 110, 201, 110, 0, + 110, 158, 113, 113, 113, 110, 110, 110, 158, 110, + 113, 114, 114, 114, 0, 158, 0, 113, 0, 114, + 110, 110, 110, 110, 158, 0, 114, 0, 110, 158, + 0, 0, 110, 0, 0, 0, 158, 116, 116, 116, + 0, 110, 110, 110, 110, 116, 117, 117, 117, 110, + 139, 139, 116, 147, 117, 118, 118, 118, 119, 119, + + 119, 117, 139, 118, 147, 121, 119, 120, 120, 120, + 118, 204, 204, 119, 121, 120, 147, 116, 121, 0, + 139, 0, 120, 0, 139, 147, 0, 121, 122, 122, + 122, 0, 123, 123, 123, 121, 122, 0, 116, 121, + 123, 204, 120, 122, 124, 124, 124, 123, 125, 126, + 205, 205, 124, 0, 0, 0, 0, 125, 126, 124, + 0, 125, 126, 120, 0, 0, 123, 0, 0, 0, + 125, 126, 0, 199, 199, 199, 0, 0, 125, 126, + 205, 124, 125, 126, 127, 127, 127, 123, 199, 0, + 199, 199, 127, 154, 154, 154, 0, 0, 0, 127, + + 0, 154, 124, 132, 132, 0, 0, 0, 154, 0, + 0, 132, 132, 132, 132, 132, 132, 155, 155, 155, + 156, 0, 0, 0, 0, 155, 0, 0, 0, 156, + 0, 0, 155, 156, 132, 132, 132, 132, 132, 0, + 0, 0, 156, 157, 157, 157, 0, 159, 159, 159, + 156, 157, 0, 0, 156, 159, 161, 0, 157, 160, + 160, 160, 159, 161, 0, 0, 0, 160, 0, 0, + 161, 0, 0, 0, 160, 162, 162, 162, 0, 161, + 169, 169, 169, 162, 161, 178, 178, 178, 169, 0, + 162, 161, 0, 178, 0, 169, 179, 179, 179, 0, + + 178, 180, 180, 180, 179, 193, 193, 193, 0, 180, + 0, 179, 0, 193, 0, 0, 180, 194, 194, 194, + 193, 0, 200, 200, 200, 194, 0, 0, 0, 180, + 200, 0, 194, 0, 0, 0, 179, 200, 0, 200, + 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 180, 0, 0, 0, 0, 0, 179, 207, 207, + 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, + 207, 207, 208, 0, 0, 208, 0, 0, 0, 208, + 208, 208, 209, 209, 209, 0, 0, 0, 0, 0, + 209, 0, 209, 0, 0, 209, 209, 209, 210, 0, + + 210, 210, 210, 211, 211, 211, 0, 0, 0, 0, + 211, 211, 211, 0, 0, 0, 211, 211, 211, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 213, 213, 0, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 214, 214, 214, 215, 0, 0, 0, + 215, 215, 215, 218, 0, 0, 218, 218, 218, 218, + 219, 219, 219, 0, 219, 0, 0, 0, 0, 0, + 219, 0, 0, 219, 219, 219, 220, 0, 0, 0, + 0, 220, 0, 0, 0, 220, 221, 0, 0, 221, + + 221, 221, 221, 222, 0, 0, 222, 222, 0, 0, + 0, 222, 0, 222, 223, 223, 223, 224, 224, 224, + 0, 0, 0, 0, 224, 224, 224, 0, 0, 0, + 224, 224, 224, 227, 0, 0, 227, 227, 227, 227, + 228, 0, 0, 0, 228, 0, 0, 0, 228, 0, + 228, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + + 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 206, 206 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; +extern int yy_flex_debug; +int yy_flex_debug = 0; + /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ @@ -606,10 +810,8 @@ static char *yy_last_accepting_cpos; #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "ada-lex.l" -#define INITIAL 0 /* FLEX lexer for Ada expressions, for GDB. - Copyright (C) 1994, 1997-1998, 2000-2003, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1994-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -631,7 +833,7 @@ char *yytext; /* the global pointer lexptr. It returns a syntactic category for */ /* each successive token and places a semantic value into yylval */ /* (ada-lval), defined by the parser. */ -#line 44 "ada-lex.l" +#line 43 "ada-lex.l" #define NUMERAL_WIDTH 256 #define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1)) @@ -645,6 +847,7 @@ static int processReal (const char *); static struct stoken processId (const char *, int); static int processAttribute (const char *); static int find_dot_all (const char *); +static void rewind_to_char (int); #undef YY_DECL #define YY_DECL static int yylex ( void ) @@ -666,9 +869,54 @@ static int find_dot_all (const char *); static int find_dot_all (const char *); + +#line 874 "ada-lex.c" + +#define INITIAL 0 #define BEFORE_QUAL_QUOTE 1 -#line 672 "ada-lex.c" +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * out_str ); + +int yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. @@ -676,65 +924,30 @@ static int find_dot_all (const char *); #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); +extern "C" int yywrap (void ); #else -extern int yywrap YY_PROTO(( void )); +extern int yywrap (void ); #endif #endif -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - + static void yyunput (int c,char *buf_ptr ); + #ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); +static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif +#ifdef __cplusplus +static int yyinput (void ); #else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 +static int input (void ); #endif -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#if __STDC__ -#ifndef __cplusplus -#include -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#endif #endif /* Amount of stuff to slurp up with each read. */ @@ -743,12 +956,11 @@ YY_MALLOC_DECL #endif /* Copy whatever the last rule matched to the standard output. */ - #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -756,9 +968,10 @@ YY_MALLOC_DECL */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ - if ( yy_current_buffer->yy_is_interactive ) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ - int c = '*', n; \ + int c = '*'; \ + unsigned n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -768,9 +981,22 @@ YY_MALLOC_DECL YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ - else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ - && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - @@ -791,12 +1017,18 @@ YY_MALLOC_DECL #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif +/* end tables serialization structures and prototypes */ + /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. @@ -813,27 +1045,29 @@ YY_MALLOC_DECL #define YY_RULE_SETUP \ YY_USER_ACTION +/** The main scanner function which does all the work. + */ YY_DECL - { +{ register yy_state_type yy_current_state; - register char *yy_cp = NULL, *yy_bp = NULL; + register char *yy_cp, *yy_bp; register int yy_act; - + #line 84 "ada-lex.l" -#line 826 "ada-lex.c" +#line 1060 "ada-lex.c" - if ( yy_init ) + if ( !(yy_init) ) { - yy_init = 0; + (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif - if ( ! yy_start ) - yy_start = 1; /* first start state */ + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; @@ -841,71 +1075,72 @@ YY_DECL if ( ! yyout ) yyout = stdout; - if ( ! yy_current_buffer ) - yy_current_buffer = - yy_create_buffer( yyin, YY_BUF_SIZE ); + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } - yy_load_buffer_state(); + yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { - yy_cp = yy_c_buf_p; + yy_cp = (yy_c_buf_p); /* Support of yytext. */ - *yy_cp = yy_hold_char; + *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; - yy_current_state = yy_start; + yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 196 ) + if ( yy_current_state >= 207 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 759 ); + while ( yy_base[yy_current_state] != 1252 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; - do_action: /* This label is used only to access EOF actions. */ - switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yy_hold_char; - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: +/* rule 1 can match eol */ YY_RULE_SETUP #line 86 "ada-lex.l" { } @@ -1026,88 +1261,93 @@ case 16: YY_RULE_SETUP #line 160 "ada-lex.l" { - while (*lexptr != 'i' && *lexptr != 'I') - lexptr -= 1; - yyrestart(NULL); + rewind_to_char ('i'); return 0; } YY_BREAK case 17: YY_RULE_SETUP -#line 167 "ada-lex.l" +#line 165 "ada-lex.l" { - /* This keyword signals the end of the expression and - will be processed separately. */ - while (*lexptr != 't' && *lexptr != 'T') - lexptr--; - yyrestart(NULL); + rewind_to_char ('t'); return 0; } YY_BREAK -/* ADA KEYWORDS */ case 18: +/* rule 18 can match eol */ YY_RULE_SETUP -#line 178 "ada-lex.l" -{ return ABS; } +#line 170 "ada-lex.l" +{ + /* This keyword signals the end of the expression and + will be processed separately. */ + rewind_to_char ('t'); + return 0; + } YY_BREAK +/* ADA KEYWORDS */ case 19: YY_RULE_SETUP #line 179 "ada-lex.l" -{ return _AND_; } +{ return ABS; } YY_BREAK case 20: YY_RULE_SETUP #line 180 "ada-lex.l" -{ return ELSE; } +{ return _AND_; } YY_BREAK case 21: YY_RULE_SETUP #line 181 "ada-lex.l" -{ return IN; } +{ return ELSE; } YY_BREAK case 22: YY_RULE_SETUP #line 182 "ada-lex.l" -{ return MOD; } +{ return IN; } YY_BREAK case 23: YY_RULE_SETUP #line 183 "ada-lex.l" -{ return NEW; } +{ return MOD; } YY_BREAK case 24: YY_RULE_SETUP #line 184 "ada-lex.l" -{ return NOT; } +{ return NEW; } YY_BREAK case 25: YY_RULE_SETUP #line 185 "ada-lex.l" -{ return NULL_PTR; } +{ return NOT; } YY_BREAK case 26: YY_RULE_SETUP #line 186 "ada-lex.l" -{ return OR; } +{ return NULL_PTR; } YY_BREAK case 27: YY_RULE_SETUP #line 187 "ada-lex.l" -{ return OTHERS; } +{ return OR; } YY_BREAK case 28: YY_RULE_SETUP #line 188 "ada-lex.l" -{ return REM; } +{ return OTHERS; } YY_BREAK case 29: YY_RULE_SETUP #line 189 "ada-lex.l" -{ return THEN; } +{ return REM; } YY_BREAK case 30: YY_RULE_SETUP #line 190 "ada-lex.l" +{ return THEN; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 191 "ada-lex.l" { return XOR; } YY_BREAK /* BOOLEAN "KEYWORDS" */ @@ -1115,93 +1355,92 @@ YY_RULE_SETUP However, the boolean type is no longer represented as an enum, so True and False are no longer defined in symbol tables. We compromise by making them keywords (when bare). */ -case 31: +case 32: YY_RULE_SETUP -#line 199 "ada-lex.l" +#line 200 "ada-lex.l" { return TRUEKEYWORD; } YY_BREAK -case 32: +case 33: YY_RULE_SETUP -#line 200 "ada-lex.l" +#line 201 "ada-lex.l" { return FALSEKEYWORD; } YY_BREAK /* ATTRIBUTES */ -case 33: +case 34: +/* rule 34 can match eol */ YY_RULE_SETUP -#line 204 "ada-lex.l" +#line 205 "ada-lex.l" { return processAttribute (yytext+1); } YY_BREAK /* PUNCTUATION */ -case 34: -YY_RULE_SETUP -#line 208 "ada-lex.l" -{ return ARROW; } - YY_BREAK case 35: YY_RULE_SETUP #line 209 "ada-lex.l" -{ return DOTDOT; } +{ return ARROW; } YY_BREAK case 36: YY_RULE_SETUP #line 210 "ada-lex.l" -{ return STARSTAR; } +{ return DOTDOT; } YY_BREAK case 37: YY_RULE_SETUP #line 211 "ada-lex.l" -{ return ASSIGN; } +{ return STARSTAR; } YY_BREAK case 38: YY_RULE_SETUP #line 212 "ada-lex.l" -{ return NOTEQUAL; } +{ return ASSIGN; } YY_BREAK case 39: YY_RULE_SETUP #line 213 "ada-lex.l" -{ return LEQ; } +{ return NOTEQUAL; } YY_BREAK case 40: YY_RULE_SETUP #line 214 "ada-lex.l" -{ return GEQ; } +{ return LEQ; } YY_BREAK case 41: YY_RULE_SETUP -#line 216 "ada-lex.l" -{ BEGIN INITIAL; return '\''; } +#line 215 "ada-lex.l" +{ return GEQ; } YY_BREAK case 42: YY_RULE_SETUP -#line 218 "ada-lex.l" -{ return yytext[0]; } +#line 217 "ada-lex.l" +{ BEGIN INITIAL; return '\''; } YY_BREAK case 43: YY_RULE_SETUP -#line 220 "ada-lex.l" +#line 219 "ada-lex.l" +{ return yytext[0]; } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 221 "ada-lex.l" { if (paren_depth == 0 && comma_terminates) { - lexptr -= 1; - yyrestart(NULL); + rewind_to_char (','); return 0; } else return ','; } YY_BREAK -case 44: +case 45: YY_RULE_SETUP #line 230 "ada-lex.l" { paren_depth += 1; return '('; } YY_BREAK -case 45: +case 46: YY_RULE_SETUP #line 231 "ada-lex.l" { if (paren_depth == 0) { - lexptr -= 1; - yyrestart(NULL); + rewind_to_char (')'); return 0; } else @@ -1211,22 +1450,25 @@ YY_RULE_SETUP } } YY_BREAK -case 46: +case 47: +/* rule 47 can match eol */ YY_RULE_SETUP -#line 244 "ada-lex.l" +#line 243 "ada-lex.l" { return DOT_ALL; } YY_BREAK -case 47: +case 48: +/* rule 48 can match eol */ YY_RULE_SETUP -#line 246 "ada-lex.l" +#line 245 "ada-lex.l" { yylval.sval = processId (yytext+1, yyleng-1); return DOT_ID; } YY_BREAK -case 48: +case 49: +/* rule 49 can match eol */ YY_RULE_SETUP -#line 251 "ada-lex.l" +#line 250 "ada-lex.l" { int all_posn = find_dot_all (yytext); @@ -1242,29 +1484,30 @@ YY_RULE_SETUP } YY_BREAK /* GDB EXPRESSION CONSTRUCTS */ -case 49: +case 50: +/* rule 50 can match eol */ YY_RULE_SETUP -#line 268 "ada-lex.l" +#line 267 "ada-lex.l" { yyless (yyleng - 2); yylval.sval = processId (yytext, yyleng); return NAME; } YY_BREAK -case 50: +case 51: YY_RULE_SETUP -#line 274 "ada-lex.l" +#line 273 "ada-lex.l" { return COLONCOLON; } YY_BREAK -case 51: +case 52: YY_RULE_SETUP -#line 276 "ada-lex.l" +#line 275 "ada-lex.l" { return yytext[0]; } YY_BREAK /* REGISTERS AND GDB CONVENIENCE VARIABLES */ -case 52: +case 53: YY_RULE_SETUP -#line 280 "ada-lex.l" +#line 279 "ada-lex.l" { yylval.sval.ptr = yytext; yylval.sval.length = yyleng; @@ -1272,17 +1515,17 @@ YY_RULE_SETUP } YY_BREAK /* CATCH-ALL ERROR CASE */ -case 53: +case 54: YY_RULE_SETUP -#line 288 "ada-lex.l" +#line 287 "ada-lex.l" { error (_("Invalid character '%s' in expression."), yytext); } YY_BREAK -case 54: +case 55: YY_RULE_SETUP -#line 289 "ada-lex.l" +#line 288 "ada-lex.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK -#line 1286 "ada-lex.c" +#line 1529 "ada-lex.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(BEFORE_QUAL_QUOTE): yyterminate(); @@ -1290,26 +1533,26 @@ case YY_STATE_EOF(BEFORE_QUAL_QUOTE): case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yy_hold_char; + *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure - * consistency between yy_current_buffer and our + * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ - yy_n_chars = yy_current_buffer->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position @@ -1319,13 +1562,13 @@ case YY_STATE_EOF(BEFORE_QUAL_QUOTE): * end-of-buffer state). Contrast this with the test * in input(). */ - if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; - yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have @@ -1338,30 +1581,30 @@ case YY_STATE_EOF(BEFORE_QUAL_QUOTE): yy_next_state = yy_try_NUL_trans( yy_current_state ); - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ - yy_cp = ++yy_c_buf_p; + yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { - yy_cp = yy_c_buf_p; + yy_cp = (yy_c_buf_p); goto yy_find_action; } } - else switch ( yy_get_next_buffer() ) + else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { - yy_did_buffer_switch_on_eof = 0; + (yy_did_buffer_switch_on_eof) = 0; - if ( yywrap() ) + if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up @@ -1372,7 +1615,7 @@ case YY_STATE_EOF(BEFORE_QUAL_QUOTE): * YY_NULL, it'll still work - another * YY_NULL will get returned. */ - yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; @@ -1380,30 +1623,30 @@ case YY_STATE_EOF(BEFORE_QUAL_QUOTE): else { - if ( ! yy_did_buffer_switch_on_eof ) + if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = - yytext_ptr + yy_amount_of_matched_text; + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: - yy_c_buf_p = - &yy_current_buffer->yy_ch_buf[yy_n_chars]; + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; @@ -1414,8 +1657,7 @@ case YY_STATE_EOF(BEFORE_QUAL_QUOTE): "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ - } /* end of yylex */ - +} /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * @@ -1424,21 +1666,20 @@ case YY_STATE_EOF(BEFORE_QUAL_QUOTE): * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ - -static int yy_get_next_buffer() - { - register char *dest = yy_current_buffer->yy_ch_buf; - register char *source = yytext_ptr; +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; - if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); - if ( yy_current_buffer->yy_fill_buffer == 0 ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. @@ -1458,34 +1699,30 @@ static int yy_get_next_buffer() /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ - yy_current_buffer->yy_n_chars = yy_n_chars = 0; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = yy_current_buffer; + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = - (int) (yy_c_buf_p - b->yy_ch_buf); + (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { @@ -1498,8 +1735,7 @@ static int yy_get_next_buffer() b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ - yyxrealloc( (void *) b->yy_ch_buf, - b->yy_buf_size + 2 ); + yyxrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ @@ -1509,35 +1745,35 @@ static int yy_get_next_buffer() YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); - yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; - num_to_read = yy_current_buffer->yy_buf_size - + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; -#endif + } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); - yy_current_buffer->yy_n_chars = yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } - if ( yy_n_chars == 0 ) + if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); + yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; - yy_current_buffer->yy_buffer_status = + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } @@ -1545,153 +1781,145 @@ static int yy_get_next_buffer() else ret_val = EOB_ACT_CONTINUE_SCAN; - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyxrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } - yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; - return ret_val; - } + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + return ret_val; +} /* yy_get_previous_state - get the state just before the EOB char was reached */ -static yy_state_type yy_get_previous_state() - { + static yy_state_type yy_get_previous_state (void) +{ register yy_state_type yy_current_state; register char *yy_cp; + + yy_current_state = (yy_start); - yy_current_state = yy_start; - - for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 196 ) + if ( yy_current_state >= 207 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; - } - +} /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ register int yy_is_jam; - register char *yy_cp = yy_c_buf_p; + register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 196 ) + if ( yy_current_state >= 207 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 195); + yy_is_jam = (yy_current_state == 206); return yy_is_jam ? 0 : yy_current_state; - } - +} -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; + *yy_cp = (yy_hold_char); - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - register int number_to_move = yy_n_chars + 2; - register char *dest = &yy_current_buffer->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - while ( source > yy_current_buffer->yy_ch_buf ) + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; - - yytext_ptr = yy_bp; - yy_hold_char = *yy_cp; - yy_c_buf_p = yy_cp; - } -#endif /* ifndef YY_NO_UNPUT */ - + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} #ifndef YY_NO_INPUT #ifdef __cplusplus -static int yyinput() + static int yyinput (void) #else -static int input() + static int input (void) #endif - { - int c; - *yy_c_buf_p = yy_hold_char; +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); - if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ - if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ - *yy_c_buf_p = '\0'; + *(yy_c_buf_p) = '\0'; else { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; - ++yy_c_buf_p; + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); - switch ( yy_get_next_buffer() ) + switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() @@ -1705,16 +1933,16 @@ static int input() */ /* Reset buffer status. */ - yyrestart( yyin ); + yyrestart(yyin ); - /* fall through */ + /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { - if ( yywrap() ) + if ( yywrap( ) ) return EOF; - if ( ! yy_did_buffer_switch_on_eof ) + if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); @@ -1724,90 +1952,92 @@ static int input() } case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = yytext_ptr + offset; + (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } - c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ - *yy_c_buf_p = '\0'; /* preserve yytext */ - yy_hold_char = *++yy_c_buf_p; - + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); return c; - } -#endif /* YY_NO_INPUT */ - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); +} +#endif /* ifndef YY_NO_INPUT */ - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); } + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - if ( yy_current_buffer == new_buffer ) +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) return; - if ( yy_current_buffer ) + if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ - *yy_c_buf_p = yy_hold_char; - yy_current_buffer->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } - yy_current_buffer = new_buffer; - yy_load_buffer_state(); + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ - yy_did_buffer_switch_on_eof = 1; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } + (yy_did_buffer_switch_on_eof) = 1; +} +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); @@ -1816,75 +2046,75 @@ int size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ - b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; - yy_init_buffer( b, file ); + yy_init_buffer(b,file ); return b; - } - +} -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) return; - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } + yyfree((void *) b->yy_ch_buf ); + yyfree((void *) b ); +} +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif - - - { - yy_flush_buffer( b ); +{ + int oerrno = errno; + + yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; -#if YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - } - + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} - { - if ( ! b ) +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) return; b->yy_n_chars = 0; @@ -1901,29 +2131,125 @@ YY_BUFFER_STATE b; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; - if ( b == yy_current_buffer ) - yy_load_buffer_state(); + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; } +} +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate xrealloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - YY_BUFFER_STATE b; + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyxrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); @@ -1937,56 +2263,51 @@ yy_size_t size; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; - yy_switch_to_buffer( b ); + yy_switch_to_buffer(b ); return b; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif +} +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; - + /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yy_flex_alloc( n ); + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - b = yy_scan_buffer( buf, n ); + b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); @@ -1996,148 +2317,196 @@ int len; b->yy_is_our_buffer = 1; return b; - } +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 #endif +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; -#endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; +/* Redefine yyless() so it works in section 3 code. */ - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); +/* Accessor methods (get/set functions) to struct members. */ - else - yy_start_stack = (int *) yyxrealloc( - (void *) yy_start_stack, new_size ); +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} - yy_start_stack[yy_start_stack_ptr++] = YY_START; +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} - BEGIN(new_state); - } -#endif +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} +/** Get the current token. + * + */ -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); +char *yyget_text (void) +{ + return yytext; +} - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; #else -static void yy_fatal_error( msg ) -char msg[]; + yyin = (FILE *) 0; + yyout = (FILE *) 0; #endif - { - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); - } + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } -/* Redefine yyless() so it works in section 3 code. */ + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + return 0; +} -/* Internal utility routines. */ +/* + * Internal utility routines. + */ #ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; - } +} #endif #ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { +static int yy_flex_strlen (yyconst char * s ) +{ register int n; for ( n = 0; s[n]; ++n ) ; return n; - } +} #endif - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { +void *yyalloc (yy_size_t size ) +{ return (void *) xmalloc( size ); - } +} -#ifdef YY_USE_PROTOS -static void *yyxrealloc( void *ptr, yy_size_t size ) -#else -static void *yyxrealloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { +void *yyxrealloc (void * ptr, yy_size_t size ) +{ /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -2146,26 +2515,17 @@ yy_size_t size; * as though doing an assignment. */ return (void *) xrealloc( (char *) ptr, size ); - } +} -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - xfree( ptr ); - } +void yyfree (void * ptr ) +{ + xfree( (char *) ptr ); /* see yyxrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 288 "ada-lex.l" -#if YY_MAIN -int main() - { - yylex(); - return 0; - } -#endif -#line 289 "ada-lex.l" #include @@ -2173,7 +2533,7 @@ int main() /* Initialize the lexer for processing new expression. */ -void +static void lexer_init (FILE *inp) { BEGIN INITIAL; @@ -2290,7 +2650,9 @@ processReal (const char *num0) /* Store a canonicalized version of NAME0[0..LEN-1] in yylval.ssym. The - resulting string is valid until the next call to ada_parse. It differs + resulting string is valid until the next call to ada_parse. If + NAME0 contains the substring "___", it is assumed to be already + encoded and the resulting name is equal to it. Otherwise, it differs from NAME0 in that: + Characters between '...' or <...> are transfered verbatim to yylval.ssym. @@ -2310,8 +2672,18 @@ processId (const char *name0, int len) int i0, i; struct stoken result; + result.ptr = name; while (len > 0 && isspace (name0[len-1])) len -= 1; + + if (strstr (name0, "___") != NULL) + { + strncpy (name, name0, len); + name[len] = '\000'; + result.length = len; + return result; + } + i = i0 = 0; while (i0 < len) { @@ -2351,7 +2723,6 @@ processId (const char *name0, int len) } name[i] = '\000'; - result.ptr = name; result.length = i; return result; } @@ -2486,6 +2857,23 @@ processAttribute (const char *str) return attributes[k].code; } +/* Back up lexptr by yyleng and then to the rightmost occurrence of + character CH, case-folded (there must be one). WARNING: since + lexptr points to the next input character that Flex has not yet + transferred to its internal buffer, the use of this function + depends on the assumption that Flex calls YY_INPUT only when it is + logically necessary to do so (thus, there is no reading ahead + farther than needed to identify the next token.) */ + +static void +rewind_to_char (int ch) +{ + lexptr -= yyleng; + while (toupper (*lexptr) != toupper (ch)) + lexptr -= 1; + yyrestart (NULL); +} + int yywrap(void) { @@ -2498,3 +2886,4 @@ dummy_function ada_flex_use[] = { (dummy_function) yyunput }; + diff --git a/contrib/gdb-7/gdb/ada-operator.def b/contrib/gdb-7/gdb/ada-operator.def index 8738250809..18a9fe672e 100644 --- a/contrib/gdb-7/gdb/ada-operator.def +++ b/contrib/gdb-7/gdb/ada-operator.def @@ -1,7 +1,6 @@ /* Ada language operator definitions for GDB, the GNU debugger. - Copyright (C) 1992, 1997-2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/ada-tasks.c b/contrib/gdb-7/gdb/ada-tasks.c index 274d83a894..25a86f61fc 100644 --- a/contrib/gdb-7/gdb/ada-tasks.c +++ b/contrib/gdb-7/gdb/ada-tasks.c @@ -1,5 +1,4 @@ -/* Copyright (C) 1992-1994, 1997-2000, 2003-2005, 2007-2012 Free - Software Foundation, Inc. +/* Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -215,6 +214,12 @@ struct ada_tasks_inferior_data above. */ CORE_ADDR known_tasks_addr; + /* Type of elements of the known task. Usually a pointer. */ + struct type *known_tasks_element; + + /* Number of elements in the known tasks array. */ + unsigned int known_tasks_length; + /* When nonzero, this flag indicates that the task_list field below is up to date. When set to zero, the list has either not been initialized, or has potentially become stale. */ @@ -774,24 +779,21 @@ add_ada_task (CORE_ADDR task_id, struct inferior *inf) it in the current inferior's TASK_LIST. Return non-zero upon success. */ static int -read_known_tasks_array (CORE_ADDR known_tasks_addr) +read_known_tasks_array (struct ada_tasks_inferior_data *data) { - const int target_ptr_byte = - gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT; - const int known_tasks_size = target_ptr_byte * MAX_NUMBER_OF_KNOWN_TASKS; + const int target_ptr_byte = TYPE_LENGTH (data->known_tasks_element); + const int known_tasks_size = target_ptr_byte * data->known_tasks_length; gdb_byte *known_tasks = alloca (known_tasks_size); int i; /* Build a new list by reading the ATCBs from the Known_Tasks array in the Ada runtime. */ - read_memory (known_tasks_addr, known_tasks, known_tasks_size); - for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++) + read_memory (data->known_tasks_addr, known_tasks, known_tasks_size); + for (i = 0; i < data->known_tasks_length; i++) { - struct type *data_ptr_type = - builtin_type (target_gdbarch)->builtin_data_ptr; CORE_ADDR task_id = extract_typed_address (known_tasks + i * target_ptr_byte, - data_ptr_type); + data->known_tasks_element); if (task_id != 0) add_ada_task (task_id, current_inferior ()); @@ -804,13 +806,10 @@ read_known_tasks_array (CORE_ADDR known_tasks_addr) the current inferior's TASK_LIST. Return non-zero upon success. */ static int -read_known_tasks_list (CORE_ADDR known_tasks_addr) +read_known_tasks_list (struct ada_tasks_inferior_data *data) { - const int target_ptr_byte = - gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT; + const int target_ptr_byte = TYPE_LENGTH (data->known_tasks_element); gdb_byte *known_tasks = alloca (target_ptr_byte); - struct type *data_ptr_type = - builtin_type (target_gdbarch)->builtin_data_ptr; CORE_ADDR task_id; const struct ada_tasks_pspace_data *pspace_data = get_ada_tasks_pspace_data (current_program_space); @@ -820,8 +819,8 @@ read_known_tasks_list (CORE_ADDR known_tasks_addr) return 0; /* Build a new list by reading the ATCBs. Read head of the list. */ - read_memory (known_tasks_addr, known_tasks, target_ptr_byte); - task_id = extract_typed_address (known_tasks, data_ptr_type); + read_memory (data->known_tasks_addr, known_tasks, target_ptr_byte); + task_id = extract_typed_address (known_tasks, data->known_tasks_element); while (task_id != 0) { struct value *tcb_value; @@ -841,51 +840,96 @@ read_known_tasks_list (CORE_ADDR known_tasks_addr) return 1; } -/* Return the address of the variable NAME that contains all the known - tasks maintained in the Ada Runtime. Return NULL if the variable - could not be found, meaning that the inferior program probably does - not use tasking. */ - -static CORE_ADDR -get_known_tasks_addr (const char *name) -{ - struct minimal_symbol *msym; - - msym = lookup_minimal_symbol (name, NULL, NULL); - if (msym == NULL) - return 0; - - return SYMBOL_VALUE_ADDRESS (msym); -} - -/* Assuming DATA is the ada-tasks' data for the current inferior, - set the known_tasks_kind and known_tasks_addr fields. Do nothing - if those fields are already set and still up to date. */ +/* Set all fields of the current inferior ada-tasks data pointed by DATA. + Do nothing if those fields are already set and still up to date. */ static void -ada_set_current_inferior_known_tasks_addr (struct ada_tasks_inferior_data *data) +ada_tasks_inferior_data_sniffer (struct ada_tasks_inferior_data *data) { - CORE_ADDR known_tasks_addr; + struct minimal_symbol *msym; + struct symbol *sym; + /* Return now if already set. */ if (data->known_tasks_kind != ADA_TASKS_UNKNOWN) return; - known_tasks_addr = get_known_tasks_addr (KNOWN_TASKS_NAME); - if (known_tasks_addr != 0) + /* Try array. */ + + msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL); + if (msym != NULL) { data->known_tasks_kind = ADA_TASKS_ARRAY; - data->known_tasks_addr = known_tasks_addr; + data->known_tasks_addr = SYMBOL_VALUE_ADDRESS (msym); + + /* Try to get pointer type and array length from the symtab. */ + sym = lookup_symbol_in_language (KNOWN_TASKS_NAME, NULL, VAR_DOMAIN, + language_c, NULL); + if (sym != NULL) + { + /* Validate. */ + struct type *type = check_typedef (SYMBOL_TYPE (sym)); + struct type *eltype = NULL; + struct type *idxtype = NULL; + + if (TYPE_CODE (type) == TYPE_CODE_ARRAY) + eltype = check_typedef (TYPE_TARGET_TYPE (type)); + if (eltype != NULL + && TYPE_CODE (eltype) == TYPE_CODE_PTR) + idxtype = check_typedef (TYPE_INDEX_TYPE (type)); + if (idxtype != NULL + && !TYPE_LOW_BOUND_UNDEFINED (idxtype) + && !TYPE_HIGH_BOUND_UNDEFINED (idxtype)) + { + data->known_tasks_element = eltype; + data->known_tasks_length = + TYPE_HIGH_BOUND (idxtype) - TYPE_LOW_BOUND (idxtype) + 1; + return; + } + } + + /* Fallback to default values. The runtime may have been stripped (as + in some distributions), but it is likely that the executable still + contains debug information on the task type (due to implicit with of + Ada.Tasking). */ + data->known_tasks_element = + builtin_type (target_gdbarch ())->builtin_data_ptr; + data->known_tasks_length = MAX_NUMBER_OF_KNOWN_TASKS; return; } - known_tasks_addr = get_known_tasks_addr (KNOWN_TASKS_LIST); - if (known_tasks_addr != 0) + + /* Try list. */ + + msym = lookup_minimal_symbol (KNOWN_TASKS_LIST, NULL, NULL); + if (msym != NULL) { data->known_tasks_kind = ADA_TASKS_LIST; - data->known_tasks_addr = known_tasks_addr; + data->known_tasks_addr = SYMBOL_VALUE_ADDRESS (msym); + data->known_tasks_length = 1; + + sym = lookup_symbol_in_language (KNOWN_TASKS_LIST, NULL, VAR_DOMAIN, + language_c, NULL); + if (sym != NULL && SYMBOL_VALUE_ADDRESS (sym) != 0) + { + /* Validate. */ + struct type *type = check_typedef (SYMBOL_TYPE (sym)); + + if (TYPE_CODE (type) == TYPE_CODE_PTR) + { + data->known_tasks_element = type; + return; + } + } + + /* Fallback to default values. */ + data->known_tasks_element = + builtin_type (target_gdbarch ())->builtin_data_ptr; + data->known_tasks_length = 1; return; } + /* Can't find tasks. */ + data->known_tasks_kind = ADA_TASKS_NOT_FOUND; data->known_tasks_addr = 0; } @@ -909,7 +953,7 @@ read_known_tasks (void) return, as we don't want a stale task list to be used... This can happen for instance when debugging a non-multitasking program after having debugged a multitasking one. */ - ada_set_current_inferior_known_tasks_addr (data); + ada_tasks_inferior_data_sniffer (data); gdb_assert (data->known_tasks_kind != ADA_TASKS_UNKNOWN); switch (data->known_tasks_kind) @@ -917,9 +961,9 @@ read_known_tasks (void) case ADA_TASKS_NOT_FOUND: /* Tasking not in use in inferior. */ return 0; case ADA_TASKS_ARRAY: - return read_known_tasks_array (data->known_tasks_addr); + return read_known_tasks_array (data); case ADA_TASKS_LIST: - return read_known_tasks_list (data->known_tasks_addr); + return read_known_tasks_list (data); } /* Step 3: Set task_list_valid_p, to avoid re-reading the Known_Tasks @@ -1128,7 +1172,7 @@ info_task (struct ui_out *uiout, char *taskno_str, struct inferior *inf) /* Print the Ada task ID. */ printf_filtered (_("Ada Task: %s\n"), - paddress (target_gdbarch, task_info->task_id)); + paddress (target_gdbarch (), task_info->task_id)); /* Print the name of the task. */ if (task_info->name[0] != '\0') diff --git a/contrib/gdb-7/gdb/ada-typeprint.c b/contrib/gdb-7/gdb/ada-typeprint.c index 97ab937d1c..2f70555c11 100644 --- a/contrib/gdb-7/gdb/ada-typeprint.c +++ b/contrib/gdb-7/gdb/ada-typeprint.c @@ -1,6 +1,5 @@ /* Support for printing Ada types for GDB, the GNU debugger. - Copyright (C) 1986, 1988-1989, 1991, 1997-2004, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -40,12 +39,15 @@ static int print_selected_record_field_types (struct type *, struct type *, int, int, - struct ui_file *, int, int); + struct ui_file *, int, int, + const struct type_print_options *); static int print_record_field_types (struct type *, struct type *, - struct ui_file *, int, int); + struct ui_file *, int, int, + const struct type_print_options *); -static void print_array_type (struct type *, struct ui_file *, int, int); +static void print_array_type (struct type *, struct ui_file *, int, int, + const struct type_print_options *); static int print_choices (struct type *, int, struct ui_file *, struct type *); @@ -76,7 +78,7 @@ decoded_type_name (struct type *type) return NULL; else { - char *raw_name = ada_type_name (type); + const char *raw_name = ada_type_name (type); char *s, *q; if (name_buffer == NULL || name_buffer_len <= strlen (raw_name)) @@ -223,9 +225,9 @@ print_dynamic_range_bound (struct type *type, const char *name, int name_len, static void print_range_type (struct type *raw_type, struct ui_file *stream) { - char *name; + const char *name; struct type *base_type; - char *subtype_info; + const char *subtype_info; gdb_assert (raw_type != NULL); name = TYPE_NAME (raw_type); @@ -274,7 +276,8 @@ static void print_enum_type (struct type *type, struct ui_file *stream) { int len = TYPE_NFIELDS (type); - int i, lastval; + int i; + LONGEST lastval; fprintf_filtered (stream, "("); wrap_here (" "); @@ -287,10 +290,11 @@ print_enum_type (struct type *type, struct ui_file *stream) fprintf_filtered (stream, ", "); wrap_here (" "); fputs_filtered (ada_enum_name (TYPE_FIELD_NAME (type, i)), stream); - if (lastval != TYPE_FIELD_BITPOS (type, i)) + if (lastval != TYPE_FIELD_ENUMVAL (type, i)) { - fprintf_filtered (stream, " => %d", TYPE_FIELD_BITPOS (type, i)); - lastval = TYPE_FIELD_BITPOS (type, i); + fprintf_filtered (stream, " => %s", + plongest (TYPE_FIELD_ENUMVAL (type, i))); + lastval = TYPE_FIELD_ENUMVAL (type, i); } lastval += 1; } @@ -322,7 +326,7 @@ print_fixed_point_type (struct type *type, struct ui_file *stream) static void print_array_type (struct type *type, struct ui_file *stream, int show, - int level) + int level, const struct type_print_options *flags) { int bitsize; int n_indices; @@ -390,7 +394,7 @@ print_array_type (struct type *type, struct ui_file *stream, int show, fprintf_filtered (stream, ") of "); wrap_here (""); ada_print_type (ada_array_element_type (type, n_indices), "", stream, - show == 0 ? 0 : show - 1, level + 1); + show == 0 ? 0 : show - 1, level + 1, flags); if (bitsize > 0) fprintf_filtered (stream, " ", bitsize); } @@ -486,7 +490,8 @@ Huh: static void print_variant_clauses (struct type *type, int field_num, struct type *outer_type, struct ui_file *stream, - int show, int level) + int show, int level, + const struct type_print_options *flags) { int i; struct type *var_type, *par_type; @@ -512,13 +517,14 @@ print_variant_clauses (struct type *type, int field_num, if (print_choices (var_type, i, stream, discr_type)) { if (print_record_field_types (TYPE_FIELD_TYPE (var_type, i), - outer_type, stream, show, level + 4) + outer_type, stream, show, level + 4, + flags) <= 0) fprintf_filtered (stream, " null;"); } else print_selected_record_field_types (var_type, outer_type, i, i, - stream, show, level + 4); + stream, show, level + 4, flags); } } @@ -532,13 +538,14 @@ print_variant_clauses (struct type *type, int field_num, static void print_variant_part (struct type *type, int field_num, struct type *outer_type, - struct ui_file *stream, int show, int level) + struct ui_file *stream, int show, int level, + const struct type_print_options *flags) { fprintf_filtered (stream, "\n%*scase %s is", level + 4, "", ada_variant_discrim_name (TYPE_FIELD_TYPE (type, field_num))); print_variant_clauses (type, field_num, outer_type, stream, show, - level + 4); + level + 4, flags); fprintf_filtered (stream, "\n%*send case;", level + 4, ""); } @@ -554,7 +561,8 @@ print_variant_part (struct type *type, int field_num, struct type *outer_type, static int print_selected_record_field_types (struct type *type, struct type *outer_type, int fld0, int fld1, - struct ui_file *stream, int show, int level) + struct ui_file *stream, int show, int level, + const struct type_print_options *flags) { int i, flds; @@ -571,10 +579,10 @@ print_selected_record_field_types (struct type *type, struct type *outer_type, ; else if (ada_is_wrapper_field (type, i)) flds += print_record_field_types (TYPE_FIELD_TYPE (type, i), type, - stream, show, level); + stream, show, level, flags); else if (ada_is_variant_part (type, i)) { - print_variant_part (type, i, outer_type, stream, show, level); + print_variant_part (type, i, outer_type, stream, show, level, flags); flds = 1; } else @@ -583,7 +591,7 @@ print_selected_record_field_types (struct type *type, struct type *outer_type, fprintf_filtered (stream, "\n%*s", level + 4, ""); ada_print_type (TYPE_FIELD_TYPE (type, i), TYPE_FIELD_NAME (type, i), - stream, show - 1, level + 4); + stream, show - 1, level + 4, flags); fprintf_filtered (stream, ";"); } } @@ -596,11 +604,12 @@ print_selected_record_field_types (struct type *type, struct type *outer_type, static int print_record_field_types (struct type *type, struct type *outer_type, - struct ui_file *stream, int show, int level) + struct ui_file *stream, int show, int level, + const struct type_print_options *flags) { return print_selected_record_field_types (type, outer_type, 0, TYPE_NFIELDS (type) - 1, - stream, show, level); + stream, show, level, flags); } @@ -610,7 +619,7 @@ print_record_field_types (struct type *type, struct type *outer_type, static void print_record_type (struct type *type0, struct ui_file *stream, int show, - int level) + int level, const struct type_print_options *flags) { struct type *parent_type; struct type *type; @@ -646,8 +655,9 @@ print_record_type (struct type *type0, struct ui_file *stream, int show, flds = 0; if (parent_type != NULL && ada_type_name (parent_type) == NULL) flds += print_record_field_types (parent_type, parent_type, - stream, show, level); - flds += print_record_field_types (type, type, stream, show, level); + stream, show, level, flags); + flds += print_record_field_types (type, type, stream, show, level, + flags); if (flds > 0) fprintf_filtered (stream, "\n%*send record", level, ""); @@ -664,7 +674,8 @@ print_record_type (struct type *type0, struct ui_file *stream, int show, number of levels of internal structure to show (see ada_print_type). */ static void print_unchecked_union_type (struct type *type, struct ui_file *stream, - int show, int level) + int show, int level, + const struct type_print_options *flags) { if (show < 0) fprintf_filtered (stream, "record (?) is ... end record"); @@ -682,7 +693,7 @@ print_unchecked_union_type (struct type *type, struct ui_file *stream, level + 12, ""); ada_print_type (TYPE_FIELD_TYPE (type, i), TYPE_FIELD_NAME (type, i), - stream, show - 1, level + 12); + stream, show - 1, level + 12, flags); fprintf_filtered (stream, ";"); } @@ -697,7 +708,8 @@ print_unchecked_union_type (struct type *type, struct ui_file *stream, for function or procedure NAME if NAME is not null. */ static void -print_func_type (struct type *type, struct ui_file *stream, const char *name) +print_func_type (struct type *type, struct ui_file *stream, const char *name, + const struct type_print_options *flags) { int i, len = TYPE_NFIELDS (type); @@ -720,7 +732,8 @@ print_func_type (struct type *type, struct ui_file *stream, const char *name) wrap_here (" "); } fprintf_filtered (stream, "a%d: ", i + 1); - ada_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0); + ada_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0, + flags); } fprintf_filtered (stream, ")"); } @@ -728,7 +741,7 @@ print_func_type (struct type *type, struct ui_file *stream, const char *name) if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID) { fprintf_filtered (stream, " return "); - ada_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0); + ada_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0, flags); } } @@ -748,7 +761,8 @@ print_func_type (struct type *type, struct ui_file *stream, const char *name) void ada_print_type (struct type *type0, const char *varstring, - struct ui_file *stream, int show, int level) + struct ui_file *stream, int show, int level, + const struct type_print_options *flags) { struct type *type = ada_check_typedef (ada_get_base_type (type0)); char *type_name = decoded_type_name (type0); @@ -778,29 +792,31 @@ ada_print_type (struct type *type0, const char *varstring, } if (ada_is_aligner_type (type)) - ada_print_type (ada_aligned_type (type), "", stream, show, level); + ada_print_type (ada_aligned_type (type), "", stream, show, level, flags); else if (ada_is_constrained_packed_array_type (type) && TYPE_CODE (type) != TYPE_CODE_PTR) - print_array_type (type, stream, show, level); + print_array_type (type, stream, show, level, flags); else switch (TYPE_CODE (type)) { default: fprintf_filtered (stream, "<"); - c_print_type (type, "", stream, show, level); + c_print_type (type, "", stream, show, level, flags); fprintf_filtered (stream, ">"); break; case TYPE_CODE_PTR: case TYPE_CODE_TYPEDEF: fprintf_filtered (stream, "access "); - ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level); + ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level, + flags); break; case TYPE_CODE_REF: fprintf_filtered (stream, " "); - ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level); + ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level, + flags); break; case TYPE_CODE_ARRAY: - print_array_type (type, stream, show, level); + print_array_type (type, stream, show, level, flags); break; case TYPE_CODE_BOOL: fprintf_filtered (stream, "(false, true)"); @@ -810,7 +826,7 @@ ada_print_type (struct type *type0, const char *varstring, print_fixed_point_type (type, stream); else { - char *name = ada_type_name (type); + const char *name = ada_type_name (type); if (!ada_is_range_type_name (name)) fprintf_filtered (stream, _("<%d-byte integer>"), @@ -845,18 +861,18 @@ ada_print_type (struct type *type0, const char *varstring, break; case TYPE_CODE_STRUCT: if (ada_is_array_descriptor_type (type)) - print_array_type (type, stream, show, level); + print_array_type (type, stream, show, level, flags); else if (ada_is_bogus_array_descriptor (type)) fprintf_filtered (stream, _("array (?) of ? ()")); else - print_record_type (type, stream, show, level); + print_record_type (type, stream, show, level, flags); break; case TYPE_CODE_UNION: - print_unchecked_union_type (type, stream, show, level); + print_unchecked_union_type (type, stream, show, level, flags); break; case TYPE_CODE_FUNC: - print_func_type (type, stream, varstring); + print_func_type (type, stream, varstring, flags); break; } } @@ -868,6 +884,6 @@ ada_print_typedef (struct type *type, struct symbol *new_symbol, struct ui_file *stream) { type = ada_check_typedef (type); - ada_print_type (type, "", stream, 0, 0); + ada_print_type (type, "", stream, 0, 0, &type_print_raw_options); fprintf_filtered (stream, "\n"); } diff --git a/contrib/gdb-7/gdb/ada-valprint.c b/contrib/gdb-7/gdb/ada-valprint.c index f43f3e3be5..5287ce5724 100644 --- a/contrib/gdb-7/gdb/ada-valprint.c +++ b/contrib/gdb-7/gdb/ada-valprint.c @@ -1,7 +1,6 @@ /* Support for printing Ada values for GDB, the GNU debugger. - Copyright (C) 1986, 1988-1989, 1991-1994, 1997, 2001-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -50,10 +49,10 @@ static int print_field_values (struct type *, const gdb_byte *, static void adjust_type_signedness (struct type *); -static int ada_val_print_1 (struct type *, const gdb_byte *, int, CORE_ADDR, - struct ui_file *, int, - const struct value *, - const struct value_print_options *); +static void ada_val_print_1 (struct type *, const gdb_byte *, int, CORE_ADDR, + struct ui_file *, int, + const struct value *, + const struct value_print_options *); /* Make TYPE unsigned if its range of values includes no negatives. */ @@ -109,7 +108,7 @@ print_optional_low_bound (struct ui_file *stream, struct type *type, return 0; break; case TYPE_CODE_ENUM: - if (low_bound == TYPE_FIELD_BITPOS (index_type, 0)) + if (low_bound == TYPE_FIELD_ENUMVAL (index_type, 0)) return 0; break; case TYPE_CODE_UNDEF: @@ -321,7 +320,6 @@ ada_print_floating (const gdb_byte *valaddr, struct type *type, { char buffer[64]; char *s, *result; - int len; struct ui_file *tmp_stream = mem_fileopen (); struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_stream); @@ -330,7 +328,6 @@ ada_print_floating (const gdb_byte *valaddr, struct type *type, do_cleanups (cleanups); result = buffer; - len = strlen (result); /* Modify for Ada rules. */ @@ -402,7 +399,7 @@ ada_print_scalar (struct type *type, LONGEST val, struct ui_file *stream) len = TYPE_NFIELDS (type); for (i = 0; i < len; i++) { - if (TYPE_FIELD_BITPOS (type, i) == val) + if (TYPE_FIELD_ENUMVAL (type, i) == val) { break; } @@ -510,10 +507,7 @@ printstr (struct ui_file *stream, struct type *elttype, const gdb_byte *string, { if (in_quotes) { - if (options->inspect_it) - fputs_filtered ("\\\", ", stream); - else - fputs_filtered ("\", ", stream); + fputs_filtered ("\", ", stream); in_quotes = 0; } fputs_filtered ("'", stream); @@ -529,10 +523,7 @@ printstr (struct ui_file *stream, struct type *elttype, const gdb_byte *string, { if (!in_quotes) { - if (options->inspect_it) - fputs_filtered ("\\\"", stream); - else - fputs_filtered ("\"", stream); + fputs_filtered ("\"", stream); in_quotes = 1; } ada_emit_char (char_at (string, i, type_len, byte_order), @@ -543,12 +534,7 @@ printstr (struct ui_file *stream, struct type *elttype, const gdb_byte *string, /* Terminate the quotes if necessary. */ if (in_quotes) - { - if (options->inspect_it) - fputs_filtered ("\\\"", stream); - else - fputs_filtered ("\"", stream); - } + fputs_filtered ("\"", stream); if (force_ellipses || i < length) fputs_filtered ("...", stream); @@ -566,10 +552,9 @@ ada_printstr (struct ui_file *stream, struct type *type, /* See val_print for a description of the various parameters of this - function; they are identical. The semantics of the return value is - also identical to val_print. */ + function; they are identical. */ -int +void ada_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR address, struct ui_file *stream, int recurse, @@ -577,35 +562,26 @@ ada_val_print (struct type *type, const gdb_byte *valaddr, const struct value_print_options *options) { volatile struct gdb_exception except; - int result = 0; /* XXX: this catches QUIT/ctrl-c as well. Isn't that busted? */ TRY_CATCH (except, RETURN_MASK_ALL) { - result = ada_val_print_1 (type, valaddr, embedded_offset, address, - stream, recurse, val, options); + ada_val_print_1 (type, valaddr, embedded_offset, address, + stream, recurse, val, options); } - - if (except.reason < 0) - result = 0; - - return result; } /* Assuming TYPE is a simple array, print the value of this array located at VALADDR + OFFSET. See ada_val_print for a description of the various - parameters of this function; they are identical. The semantics - of the return value is also identical to ada_val_print. */ + parameters of this function; they are identical. */ -static int +static void ada_val_print_array (struct type *type, const gdb_byte *valaddr, int offset, CORE_ADDR address, struct ui_file *stream, int recurse, const struct value *val, const struct value_print_options *options) { - int result = 0; - /* For an array of chars, print with string syntax. */ if (ada_is_string_type (type) && (options->format == 0 || options->format == 's')) @@ -644,7 +620,6 @@ ada_val_print_array (struct type *type, const gdb_byte *valaddr, } printstr (stream, elttype, valaddr + offset, len, 0, eltlen, options); - result = len; } else { @@ -658,24 +633,20 @@ ada_val_print_array (struct type *type, const gdb_byte *valaddr, stream, recurse, val, options, 0); fprintf_filtered (stream, ")"); } - - return result; } /* See the comment on ada_val_print. This function differs in that it does not catch evaluation errors (leaving that to ada_val_print). */ -static int +static void ada_val_print_1 (struct type *type, const gdb_byte *valaddr, int offset, CORE_ADDR address, struct ui_file *stream, int recurse, const struct value *original_value, const struct value_print_options *options) { - unsigned int len; int i; struct type *elttype; - LONGEST val; int offset_aligned; type = ada_check_typedef (type); @@ -684,11 +655,14 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, || (ada_is_constrained_packed_array_type (type) && TYPE_CODE (type) != TYPE_CODE_PTR)) { - int retn; struct value *mark = value_mark (); struct value *val; val = value_from_contents_and_address (type, valaddr + offset, address); + /* If this is a reference, coerce it now. This helps taking care + of the case where ADDRESS is meaningless because original_value + was not an lval. */ + val = coerce_ref (val); if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) /* array access type. */ val = ada_coerce_to_simple_array_ptr (val); else @@ -697,16 +671,15 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, { gdb_assert (TYPE_CODE (type) == TYPE_CODE_TYPEDEF); fprintf_filtered (stream, "0x0"); - retn = 0; } else - retn = ada_val_print_1 (value_type (val), - value_contents_for_printing (val), - value_embedded_offset (val), - value_address (val), stream, recurse, - val, options); + ada_val_print_1 (value_type (val), + value_contents_for_printing (val), + value_embedded_offset (val), + value_address (val), stream, recurse, + val, options); value_free_to_mark (mark); - return retn; + return; } offset_aligned = offset + ada_aligned_value_addr (type, valaddr) - valaddr; @@ -715,13 +688,14 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, switch (TYPE_CODE (type)) { default: - return c_val_print (type, valaddr, offset, address, stream, - recurse, original_value, options); + c_val_print (type, valaddr, offset, address, stream, + recurse, original_value, options); + break; case TYPE_CODE_PTR: { - int ret = c_val_print (type, valaddr, offset, address, - stream, recurse, original_value, options); + c_val_print (type, valaddr, offset, address, + stream, recurse, original_value, options); if (ada_is_tag_type (type)) { @@ -733,9 +707,8 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, if (name != NULL) fprintf_filtered (stream, " (%s)", name); - return 0; - } - return ret; + } + return; } case TYPE_CODE_INT: @@ -743,11 +716,10 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, if (ada_is_fixed_point_type (type)) { LONGEST v = unpack_long (type, valaddr + offset_aligned); - int len = TYPE_LENGTH (type); - fprintf_filtered (stream, len < 4 ? "%.11g" : "%.17g", + fprintf_filtered (stream, TYPE_LENGTH (type) < 4 ? "%.11g" : "%.17g", (double) ada_fixed_to_float (type, v)); - return 0; + return; } else if (TYPE_CODE (type) == TYPE_CODE_RANGE) { @@ -763,16 +735,17 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, = value_from_contents_and_address (type, valaddr + offset, 0); struct value *v = value_cast (target_type, v1); - return ada_val_print_1 (target_type, - value_contents_for_printing (v), - value_embedded_offset (v), 0, - stream, recurse + 1, v, options); + ada_val_print_1 (target_type, + value_contents_for_printing (v), + value_embedded_offset (v), 0, + stream, recurse + 1, v, options); } else - return ada_val_print_1 (TYPE_TARGET_TYPE (type), - valaddr, offset, - address, stream, recurse, - original_value, options); + ada_val_print_1 (TYPE_TARGET_TYPE (type), + valaddr, offset, + address, stream, recurse, + original_value, options); + return; } else { @@ -817,53 +790,53 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, ada_printchar (c, type, stream); } } - return 0; + return; } case TYPE_CODE_ENUM: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, offset_aligned, - original_value, options, 0, stream); - break; - } - len = TYPE_NFIELDS (type); - val = unpack_long (type, valaddr + offset_aligned); - for (i = 0; i < len; i++) - { - QUIT; - if (val == TYPE_FIELD_BITPOS (type, i)) - { - break; - } - } - if (i < len) - { - const char *name = ada_enum_name (TYPE_FIELD_NAME (type, i)); - - if (name[0] == '\'') - fprintf_filtered (stream, "%ld %s", (long) val, name); - else - fputs_filtered (name, stream); - } - else - { - print_longest (stream, 'd', 0, val); - } - break; + { + unsigned int len; + LONGEST val; - case TYPE_CODE_FLAGS: - if (options->format) - val_print_scalar_formatted (type, valaddr, offset_aligned, - original_value, options, 0, stream); - else - val_print_type_code_flags (type, valaddr + offset_aligned, stream); - break; + if (options->format) + { + val_print_scalar_formatted (type, valaddr, offset_aligned, + original_value, options, 0, stream); + break; + } + len = TYPE_NFIELDS (type); + val = unpack_long (type, valaddr + offset_aligned); + for (i = 0; i < len; i++) + { + QUIT; + if (val == TYPE_FIELD_ENUMVAL (type, i)) + { + break; + } + } + if (i < len) + { + const char *name = ada_enum_name (TYPE_FIELD_NAME (type, i)); + + if (name[0] == '\'') + fprintf_filtered (stream, "%ld %s", (long) val, name); + else + fputs_filtered (name, stream); + } + else + { + print_longest (stream, 'd', 0, val); + } + break; + } case TYPE_CODE_FLT: if (options->format) - return c_val_print (type, valaddr, offset, address, stream, - recurse, original_value, options); + { + c_val_print (type, valaddr, offset, address, stream, + recurse, original_value, options); + return; + } else ada_print_floating (valaddr + offset, type, stream); break; @@ -873,19 +846,20 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, if (ada_is_bogus_array_descriptor (type)) { fprintf_filtered (stream, "(...?)"); - return 0; + return; } else { print_record (type, valaddr, offset_aligned, stream, recurse, original_value, options); - return 0; + return; } case TYPE_CODE_ARRAY: - return ada_val_print_array (type, valaddr, offset_aligned, - address, stream, recurse, original_value, - options); + ada_val_print_array (type, valaddr, offset_aligned, + address, stream, recurse, original_value, + options); + return; case TYPE_CODE_REF: /* For references, the debugger is expected to print the value as @@ -903,6 +877,9 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, deref_val = coerce_ref_if_computed (original_value); if (deref_val) { + if (ada_is_tagged_type (value_type (deref_val), 1)) + deref_val = ada_tag_value_at_base_address (deref_val); + common_val_print (deref_val, stream, recurse + 1, options, current_language); break; @@ -911,11 +888,14 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, deref_val_int = unpack_pointer (type, valaddr + offset_aligned); if (deref_val_int != 0) { - struct value *deref_val = + deref_val = ada_value_ind (value_from_pointer (lookup_pointer_type (elttype), deref_val_int)); + if (ada_is_tagged_type (value_type (deref_val), 1)) + deref_val = ada_tag_value_at_base_address (deref_val); + val_print (value_type (deref_val), value_contents_for_printing (deref_val), value_embedded_offset (deref_val), @@ -931,7 +911,6 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr, break; } gdb_flush (stream); - return 0; } static int @@ -959,7 +938,7 @@ print_variant_part (struct type *type, int field_num, comma_needed, outer_type, outer_offset); } -int +void ada_value_print (struct value *val0, struct ui_file *stream, const struct value_print_options *options) { @@ -999,14 +978,14 @@ ada_value_print (struct value *val0, struct ui_file *stream, fprintf_filtered (stream, "("); type_print (type, "", stream, -1); fprintf_filtered (stream, ") (...?)"); - return 0; + return; } opts = *options; opts.deref_ref = 1; - return (val_print (type, value_contents_for_printing (val), - value_embedded_offset (val), address, - stream, 0, val, &opts, current_language)); + val_print (type, value_contents_for_printing (val), + value_embedded_offset (val), address, + stream, 0, val, &opts, current_language); } static void @@ -1097,29 +1076,14 @@ print_field_values (struct type *type, const gdb_byte *valaddr, { wrap_here (n_spaces (2 + 2 * recurse)); } - if (options->inspect_it) - { - if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR) - fputs_filtered ("\"( ptr \"", stream); - else - fputs_filtered ("\"( nodef \"", stream); - fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), - language_cplus, DMGL_NO_OPTS); - fputs_filtered ("\" \"", stream); - fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), - language_cplus, DMGL_NO_OPTS); - fputs_filtered ("\") \"", stream); - } - else - { - annotate_field_begin (TYPE_FIELD_TYPE (type, i)); - fprintf_filtered (stream, "%.*s", - ada_name_prefix_len (TYPE_FIELD_NAME (type, i)), - TYPE_FIELD_NAME (type, i)); - annotate_field_name_end (); - fputs_filtered (" => ", stream); - annotate_field_value (); - } + + annotate_field_begin (TYPE_FIELD_TYPE (type, i)); + fprintf_filtered (stream, "%.*s", + ada_name_prefix_len (TYPE_FIELD_NAME (type, i)), + TYPE_FIELD_NAME (type, i)); + annotate_field_name_end (); + fputs_filtered (" => ", stream); + annotate_field_value (); if (TYPE_FIELD_PACKED (type, i)) { diff --git a/contrib/gdb-7/gdb/ada-varobj.c b/contrib/gdb-7/gdb/ada-varobj.c new file mode 100644 index 0000000000..53d8a9c6b4 --- /dev/null +++ b/contrib/gdb-7/gdb/ada-varobj.c @@ -0,0 +1,888 @@ +/* varobj support for Ada. + + Copyright (C) 2012-2013 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 "ada-varobj.h" +#include "ada-lang.h" +#include "language.h" +#include "valprint.h" + +/* Implementation principle used in this unit: + + For our purposes, the meat of the varobj object is made of two + elements: The varobj's (struct) value, and the varobj's (struct) + type. In most situations, the varobj has a non-NULL value, and + the type becomes redundant, as it can be directly derived from + the value. In the initial implementation of this unit, most + routines would only take a value, and return a value. + + But there are many situations where it is possible for a varobj + to have a NULL value. For instance, if the varobj becomes out of + scope. Or better yet, when the varobj is the child of another + NULL pointer varobj. In that situation, we must rely on the type + instead of the value to create the child varobj. + + That's why most functions below work with a (value, type) pair. + The value may or may not be NULL. But the type is always expected + to be set. When the value is NULL, then we work with the type + alone, and keep the value NULL. But when the value is not NULL, + then we work using the value, because it provides more information. + But we still always set the type as well, even if that type could + easily be derived from the value. The reason behind this is that + it allows the code to use the type without having to worry about + it being set or not. It makes the code clearer. */ + +/* A convenience function that decodes the VALUE_PTR/TYPE_PTR couple: + If there is a value (*VALUE_PTR not NULL), then perform the decoding + using it, and compute the associated type from the resulting value. + Otherwise, compute a static approximation of *TYPE_PTR, leaving + *VALUE_PTR unchanged. + + The results are written in place. */ + +static void +ada_varobj_decode_var (struct value **value_ptr, struct type **type_ptr) +{ + if (*value_ptr) + { + *value_ptr = ada_get_decoded_value (*value_ptr); + *type_ptr = ada_check_typedef (value_type (*value_ptr)); + } + else + *type_ptr = ada_get_decoded_type (*type_ptr); +} + +/* Return a string containing an image of the given scalar value. + VAL is the numeric value, while TYPE is the value's type. + This is useful for plain integers, of course, but even more + so for enumerated types. + + The result should be deallocated by xfree after use. */ + +static char * +ada_varobj_scalar_image (struct type *type, LONGEST val) +{ + struct ui_file *buf = mem_fileopen (); + struct cleanup *cleanups = make_cleanup_ui_file_delete (buf); + char *result; + + ada_print_scalar (type, val, buf); + result = ui_file_xstrdup (buf, NULL); + do_cleanups (cleanups); + + return result; +} + +/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair designates + a struct or union, compute the (CHILD_VALUE, CHILD_TYPE) couple + corresponding to the field number FIELDNO. */ + +static void +ada_varobj_struct_elt (struct value *parent_value, + struct type *parent_type, + int fieldno, + struct value **child_value, + struct type **child_type) +{ + struct value *value = NULL; + struct type *type = NULL; + + if (parent_value) + { + value = value_field (parent_value, fieldno); + type = value_type (value); + } + else + type = TYPE_FIELD_TYPE (parent_type, fieldno); + + if (child_value) + *child_value = value; + if (child_type) + *child_type = type; +} + +/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair is a pointer or + reference, return a (CHILD_VALUE, CHILD_TYPE) couple corresponding + to the dereferenced value. */ + +static void +ada_varobj_ind (struct value *parent_value, + struct type *parent_type, + struct value **child_value, + struct type **child_type) +{ + struct value *value = NULL; + struct type *type = NULL; + + if (ada_is_array_descriptor_type (parent_type)) + { + /* This can only happen when PARENT_VALUE is NULL. Otherwise, + ada_get_decoded_value would have transformed our parent_type + into a simple array pointer type. */ + gdb_assert (parent_value == NULL); + gdb_assert (TYPE_CODE (parent_type) == TYPE_CODE_TYPEDEF); + + /* Decode parent_type by the equivalent pointer to (decoded) + array. */ + while (TYPE_CODE (parent_type) == TYPE_CODE_TYPEDEF) + parent_type = TYPE_TARGET_TYPE (parent_type); + parent_type = ada_coerce_to_simple_array_type (parent_type); + parent_type = lookup_pointer_type (parent_type); + } + + /* If parent_value is a null pointer, then only perform static + dereferencing. We cannot dereference null pointers. */ + if (parent_value && value_as_address (parent_value) == 0) + parent_value = NULL; + + if (parent_value) + { + value = ada_value_ind (parent_value); + type = value_type (value); + } + else + type = TYPE_TARGET_TYPE (parent_type); + + if (child_value) + *child_value = value; + if (child_type) + *child_type = type; +} + +/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair is a simple + array (TYPE_CODE_ARRAY), return the (CHILD_VALUE, CHILD_TYPE) + pair corresponding to the element at ELT_INDEX. */ + +static void +ada_varobj_simple_array_elt (struct value *parent_value, + struct type *parent_type, + int elt_index, + struct value **child_value, + struct type **child_type) +{ + struct value *value = NULL; + struct type *type = NULL; + + if (parent_value) + { + struct value *index_value = + value_from_longest (TYPE_INDEX_TYPE (parent_type), elt_index); + + value = ada_value_subscript (parent_value, 1, &index_value); + type = value_type (value); + } + else + type = TYPE_TARGET_TYPE (parent_type); + + if (child_value) + *child_value = value; + if (child_type) + *child_type = type; +} + +/* Given the decoded value and decoded type of a variable object, + adjust the value and type to those necessary for getting children + of the variable object. + + The replacement is performed in place. */ + +static void +ada_varobj_adjust_for_child_access (struct value **value, + struct type **type) +{ + /* Pointers to struct/union types are special: Instead of having + one child (the struct), their children are the components of + the struct/union type. We handle this situation by dereferencing + the (value, type) couple. */ + if (TYPE_CODE (*type) == TYPE_CODE_PTR + && (TYPE_CODE (TYPE_TARGET_TYPE (*type)) == TYPE_CODE_STRUCT + || TYPE_CODE (TYPE_TARGET_TYPE (*type)) == TYPE_CODE_UNION) + && !ada_is_array_descriptor_type (TYPE_TARGET_TYPE (*type)) + && !ada_is_constrained_packed_array_type (TYPE_TARGET_TYPE (*type))) + ada_varobj_ind (*value, *type, value, type); +} + +/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair is an array + (any type of array, "simple" or not), return the number of children + that this array contains. */ + +static int +ada_varobj_get_array_number_of_children (struct value *parent_value, + struct type *parent_type) +{ + LONGEST lo, hi; + + if (!get_array_bounds (parent_type, &lo, &hi)) + { + /* Could not get the array bounds. Pretend this is an empty array. */ + warning (_("unable to get bounds of array, assuming null array")); + return 0; + } + + /* Ada allows the upper bound to be less than the lower bound, + in order to specify empty arrays... */ + if (hi < lo) + return 0; + + return hi - lo + 1; +} + +/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair is a struct or + union, return the number of children this struct contains. */ + +static int +ada_varobj_get_struct_number_of_children (struct value *parent_value, + struct type *parent_type) +{ + int n_children = 0; + int i; + + gdb_assert (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT + || TYPE_CODE (parent_type) == TYPE_CODE_UNION); + + for (i = 0; i < TYPE_NFIELDS (parent_type); i++) + { + if (ada_is_ignored_field (parent_type, i)) + continue; + + if (ada_is_wrapper_field (parent_type, i)) + { + struct value *elt_value; + struct type *elt_type; + + ada_varobj_struct_elt (parent_value, parent_type, i, + &elt_value, &elt_type); + if (ada_is_tagged_type (elt_type, 0)) + { + /* We must not use ada_varobj_get_number_of_children + to determine is element's number of children, because + this function first calls ada_varobj_decode_var, + which "fixes" the element. For tagged types, this + includes reading the object's tag to determine its + real type, which happens to be the parent_type, and + leads to an infinite loop (because the element gets + fixed back into the parent). */ + n_children += ada_varobj_get_struct_number_of_children + (elt_value, elt_type); + } + else + n_children += ada_varobj_get_number_of_children (elt_value, elt_type); + } + else if (ada_is_variant_part (parent_type, i)) + { + /* In normal situations, the variant part of the record should + have been "fixed". Or, in other words, it should have been + replaced by the branch of the variant part that is relevant + for our value. But there are still situations where this + can happen, however (Eg. when our parent is a NULL pointer). + We do not support showing this part of the record for now, + so just pretend this field does not exist. */ + } + else + n_children++; + } + + return n_children; +} + +/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair designates + a pointer, return the number of children this pointer has. */ + +static int +ada_varobj_get_ptr_number_of_children (struct value *parent_value, + struct type *parent_type) +{ + struct type *child_type = TYPE_TARGET_TYPE (parent_type); + + /* Pointer to functions and to void do not have a child, since + you cannot print what they point to. */ + if (TYPE_CODE (child_type) == TYPE_CODE_FUNC + || TYPE_CODE (child_type) == TYPE_CODE_VOID) + return 0; + + /* All other types have 1 child. */ + return 1; +} + +/* Return the number of children for the (PARENT_VALUE, PARENT_TYPE) + pair. */ + +int +ada_varobj_get_number_of_children (struct value *parent_value, + struct type *parent_type) +{ + ada_varobj_decode_var (&parent_value, &parent_type); + ada_varobj_adjust_for_child_access (&parent_value, &parent_type); + + /* A typedef to an array descriptor in fact represents a pointer + to an unconstrained array. These types always have one child + (the unconstrained array). */ + if (ada_is_array_descriptor_type (parent_type) + && TYPE_CODE (parent_type) == TYPE_CODE_TYPEDEF) + return 1; + + if (TYPE_CODE (parent_type) == TYPE_CODE_ARRAY) + return ada_varobj_get_array_number_of_children (parent_value, + parent_type); + + if (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT + || TYPE_CODE (parent_type) == TYPE_CODE_UNION) + return ada_varobj_get_struct_number_of_children (parent_value, + parent_type); + + if (TYPE_CODE (parent_type) == TYPE_CODE_PTR) + return ada_varobj_get_ptr_number_of_children (parent_value, + parent_type); + + /* All other types have no child. */ + return 0; +} + +/* Describe the child of the (PARENT_VALUE, PARENT_TYPE) pair + whose index is CHILD_INDEX: + + - If CHILD_NAME is not NULL, then a copy of the child's name + is saved in *CHILD_NAME. This copy must be deallocated + with xfree after use. + + - If CHILD_VALUE is not NULL, then save the child's value + in *CHILD_VALUE. Same thing for the child's type with + CHILD_TYPE if not NULL. + + - If CHILD_PATH_EXPR is not NULL, then compute the child's + path expression. The resulting string must be deallocated + after use with xfree. + + Computing the child's path expression requires the PARENT_PATH_EXPR + to be non-NULL. Otherwise, PARENT_PATH_EXPR may be null if + CHILD_PATH_EXPR is NULL. + + PARENT_NAME is the name of the parent, and should never be NULL. */ + +static void ada_varobj_describe_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + const char *parent_path_expr, + int child_index, + char **child_name, + struct value **child_value, + struct type **child_type, + char **child_path_expr); + +/* Same as ada_varobj_describe_child, but limited to struct/union + objects. */ + +static void +ada_varobj_describe_struct_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + const char *parent_path_expr, + int child_index, + char **child_name, + struct value **child_value, + struct type **child_type, + char **child_path_expr) +{ + int fieldno; + int childno = 0; + + gdb_assert (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT); + + for (fieldno = 0; fieldno < TYPE_NFIELDS (parent_type); fieldno++) + { + if (ada_is_ignored_field (parent_type, fieldno)) + continue; + + if (ada_is_wrapper_field (parent_type, fieldno)) + { + struct value *elt_value; + struct type *elt_type; + int elt_n_children; + + ada_varobj_struct_elt (parent_value, parent_type, fieldno, + &elt_value, &elt_type); + if (ada_is_tagged_type (elt_type, 0)) + { + /* Same as in ada_varobj_get_struct_number_of_children: + For tagged types, we must be careful to not call + ada_varobj_get_number_of_children, to prevent our + element from being fixed back into the parent. */ + elt_n_children = ada_varobj_get_struct_number_of_children + (elt_value, elt_type); + } + else + elt_n_children = + ada_varobj_get_number_of_children (elt_value, elt_type); + + /* Is the child we're looking for one of the children + of this wrapper field? */ + if (child_index - childno < elt_n_children) + { + if (ada_is_tagged_type (elt_type, 0)) + { + /* Same as in ada_varobj_get_struct_number_of_children: + For tagged types, we must be careful to not call + ada_varobj_describe_child, to prevent our element + from being fixed back into the parent. */ + ada_varobj_describe_struct_child + (elt_value, elt_type, parent_name, parent_path_expr, + child_index - childno, child_name, child_value, + child_type, child_path_expr); + } + else + ada_varobj_describe_child (elt_value, elt_type, + parent_name, parent_path_expr, + child_index - childno, + child_name, child_value, + child_type, child_path_expr); + return; + } + + /* The child we're looking for is beyond this wrapper + field, so skip all its children. */ + childno += elt_n_children; + continue; + } + else if (ada_is_variant_part (parent_type, fieldno)) + { + /* In normal situations, the variant part of the record should + have been "fixed". Or, in other words, it should have been + replaced by the branch of the variant part that is relevant + for our value. But there are still situations where this + can happen, however (Eg. when our parent is a NULL pointer). + We do not support showing this part of the record for now, + so just pretend this field does not exist. */ + continue; + } + + if (childno == child_index) + { + if (child_name) + { + /* The name of the child is none other than the field's + name, except that we need to strip suffixes from it. + For instance, fields with alignment constraints will + have an __XVA suffix added to them. */ + const char *field_name = TYPE_FIELD_NAME (parent_type, fieldno); + int child_name_len = ada_name_prefix_len (field_name); + + *child_name = xstrprintf ("%.*s", child_name_len, field_name); + } + + if (child_value && parent_value) + ada_varobj_struct_elt (parent_value, parent_type, fieldno, + child_value, NULL); + + if (child_type) + ada_varobj_struct_elt (parent_value, parent_type, fieldno, + NULL, child_type); + + if (child_path_expr) + { + /* The name of the child is none other than the field's + name, except that we need to strip suffixes from it. + For instance, fields with alignment constraints will + have an __XVA suffix added to them. */ + const char *field_name = TYPE_FIELD_NAME (parent_type, fieldno); + int child_name_len = ada_name_prefix_len (field_name); + + *child_path_expr = + xstrprintf ("(%s).%.*s", parent_path_expr, + child_name_len, field_name); + } + + return; + } + + childno++; + } + + /* Something went wrong. Either we miscounted the number of + children, or CHILD_INDEX was too high. But we should never + reach here. We don't have enough information to recover + nicely, so just raise an assertion failure. */ + gdb_assert_not_reached ("unexpected code path"); +} + +/* Same as ada_varobj_describe_child, but limited to pointer objects. + + Note that CHILD_INDEX is unused in this situation, but still provided + for consistency of interface with other routines describing an object's + child. */ + +static void +ada_varobj_describe_ptr_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + const char *parent_path_expr, + int child_index, + char **child_name, + struct value **child_value, + struct type **child_type, + char **child_path_expr) +{ + if (child_name) + *child_name = xstrprintf ("%s.all", parent_name); + + if (child_value && parent_value) + ada_varobj_ind (parent_value, parent_type, child_value, NULL); + + if (child_type) + ada_varobj_ind (parent_value, parent_type, NULL, child_type); + + if (child_path_expr) + *child_path_expr = xstrprintf ("(%s).all", parent_path_expr); +} + +/* Same as ada_varobj_describe_child, limited to simple array objects + (TYPE_CODE_ARRAY only). + + Assumes that the (PARENT_VALUE, PARENT_TYPE) pair is properly decoded. + This is done by ada_varobj_describe_child before calling us. */ + +static void +ada_varobj_describe_simple_array_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + const char *parent_path_expr, + int child_index, + char **child_name, + struct value **child_value, + struct type **child_type, + char **child_path_expr) +{ + struct type *index_desc_type; + struct type *index_type; + int real_index; + + gdb_assert (TYPE_CODE (parent_type) == TYPE_CODE_ARRAY); + + index_desc_type = ada_find_parallel_type (parent_type, "___XA"); + ada_fixup_array_indexes_type (index_desc_type); + if (index_desc_type) + index_type = TYPE_FIELD_TYPE (index_desc_type, 0); + else + index_type = TYPE_INDEX_TYPE (parent_type); + real_index = child_index + ada_discrete_type_low_bound (index_type); + + if (child_name) + *child_name = ada_varobj_scalar_image (index_type, real_index); + + if (child_value && parent_value) + ada_varobj_simple_array_elt (parent_value, parent_type, real_index, + child_value, NULL); + + if (child_type) + ada_varobj_simple_array_elt (parent_value, parent_type, real_index, + NULL, child_type); + + if (child_path_expr) + { + char *index_img = ada_varobj_scalar_image (index_type, real_index); + struct cleanup *cleanups = make_cleanup (xfree, index_img); + + /* Enumeration litterals by themselves are potentially ambiguous. + For instance, consider the following package spec: + + package Pck is + type Color is (Red, Green, Blue, White); + type Blood_Cells is (White, Red); + end Pck; + + In this case, the litteral "red" for instance, or even + the fully-qualified litteral "pck.red" cannot be resolved + by itself. Type qualification is needed to determine which + enumeration litterals should be used. + + The following variable will be used to contain the name + of the array index type when such type qualification is + needed. */ + const char *index_type_name = NULL; + + /* If the index type is a range type, find the base type. */ + while (TYPE_CODE (index_type) == TYPE_CODE_RANGE) + index_type = TYPE_TARGET_TYPE (index_type); + + if (TYPE_CODE (index_type) == TYPE_CODE_ENUM + || TYPE_CODE (index_type) == TYPE_CODE_BOOL) + { + index_type_name = ada_type_name (index_type); + if (index_type_name) + index_type_name = ada_decode (index_type_name); + } + + if (index_type_name != NULL) + *child_path_expr = + xstrprintf ("(%s)(%.*s'(%s))", parent_path_expr, + ada_name_prefix_len (index_type_name), + index_type_name, index_img); + else + *child_path_expr = + xstrprintf ("(%s)(%s)", parent_path_expr, index_img); + do_cleanups (cleanups); + } +} + +/* See description at declaration above. */ + +static void +ada_varobj_describe_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + const char *parent_path_expr, + int child_index, + char **child_name, + struct value **child_value, + struct type **child_type, + char **child_path_expr) +{ + /* We cannot compute the child's path expression without + the parent's path expression. This is a pre-condition + for calling this function. */ + if (child_path_expr) + gdb_assert (parent_path_expr != NULL); + + ada_varobj_decode_var (&parent_value, &parent_type); + ada_varobj_adjust_for_child_access (&parent_value, &parent_type); + + if (child_name) + *child_name = NULL; + if (child_value) + *child_value = NULL; + if (child_type) + *child_type = NULL; + if (child_path_expr) + *child_path_expr = NULL; + + if (ada_is_array_descriptor_type (parent_type) + && TYPE_CODE (parent_type) == TYPE_CODE_TYPEDEF) + { + ada_varobj_describe_ptr_child (parent_value, parent_type, + parent_name, parent_path_expr, + child_index, child_name, + child_value, child_type, + child_path_expr); + return; + } + + if (TYPE_CODE (parent_type) == TYPE_CODE_ARRAY) + { + ada_varobj_describe_simple_array_child + (parent_value, parent_type, parent_name, parent_path_expr, + child_index, child_name, child_value, child_type, + child_path_expr); + return; + } + + if (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT) + { + ada_varobj_describe_struct_child (parent_value, parent_type, + parent_name, parent_path_expr, + child_index, child_name, + child_value, child_type, + child_path_expr); + return; + } + + if (TYPE_CODE (parent_type) == TYPE_CODE_PTR) + { + ada_varobj_describe_ptr_child (parent_value, parent_type, + parent_name, parent_path_expr, + child_index, child_name, + child_value, child_type, + child_path_expr); + return; + } + + /* It should never happen. But rather than crash, report dummy names + and return a NULL child_value. */ + if (child_name) + *child_name = xstrdup ("???"); +} + +/* Return the name of the child number CHILD_INDEX of the (PARENT_VALUE, + PARENT_TYPE) pair. PARENT_NAME is the name of the PARENT. + + The result should be deallocated after use with xfree. */ + +char * +ada_varobj_get_name_of_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, int child_index) +{ + char *child_name; + + ada_varobj_describe_child (parent_value, parent_type, parent_name, + NULL, child_index, &child_name, NULL, + NULL, NULL); + return child_name; +} + +/* Return the path expression of the child number CHILD_INDEX of + the (PARENT_VALUE, PARENT_TYPE) pair. PARENT_NAME is the name + of the parent, and PARENT_PATH_EXPR is the parent's path expression. + Both must be non-NULL. + + The result must be deallocated after use with xfree. */ + +char * +ada_varobj_get_path_expr_of_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + const char *parent_path_expr, + int child_index) +{ + char *child_path_expr; + + ada_varobj_describe_child (parent_value, parent_type, parent_name, + parent_path_expr, child_index, NULL, + NULL, NULL, &child_path_expr); + + return child_path_expr; +} + +/* Return the value of child number CHILD_INDEX of the (PARENT_VALUE, + PARENT_TYPE) pair. PARENT_NAME is the name of the parent. */ + +struct value * +ada_varobj_get_value_of_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, int child_index) +{ + struct value *child_value; + + ada_varobj_describe_child (parent_value, parent_type, parent_name, + NULL, child_index, NULL, &child_value, + NULL, NULL); + + return child_value; +} + +/* Return the type of child number CHILD_INDEX of the (PARENT_VALUE, + PARENT_TYPE) pair. */ + +struct type * +ada_varobj_get_type_of_child (struct value *parent_value, + struct type *parent_type, + int child_index) +{ + struct type *child_type; + + ada_varobj_describe_child (parent_value, parent_type, NULL, NULL, + child_index, NULL, NULL, &child_type, NULL); + + return child_type; +} + +/* Return a string that contains the image of the given VALUE, using + the print options OPTS as the options for formatting the result. + + The resulting string must be deallocated after use with xfree. */ + +static char * +ada_varobj_get_value_image (struct value *value, + struct value_print_options *opts) +{ + char *result; + struct ui_file *buffer; + struct cleanup *old_chain; + + buffer = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (buffer); + + common_val_print (value, buffer, 0, opts, current_language); + result = ui_file_xstrdup (buffer, NULL); + + do_cleanups (old_chain); + return result; +} + +/* Assuming that the (VALUE, TYPE) pair designates an array varobj, + return a string that is suitable for use in the "value" field of + the varobj output. Most of the time, this is the number of elements + in the array inside square brackets, but there are situations where + it's useful to add more info. + + OPTS are the print options used when formatting the result. + + The result should be deallocated after use using xfree. */ + +static char * +ada_varobj_get_value_of_array_variable (struct value *value, + struct type *type, + struct value_print_options *opts) +{ + char *result; + const int numchild = ada_varobj_get_array_number_of_children (value, type); + + /* If we have a string, provide its contents in the "value" field. + Otherwise, the only other way to inspect the contents of the string + is by looking at the value of each element, as in any other array, + which is not very convenient... */ + if (value + && ada_is_string_type (type) + && (opts->format == 0 || opts->format == 's')) + { + char *str; + struct cleanup *old_chain; + + str = ada_varobj_get_value_image (value, opts); + old_chain = make_cleanup (xfree, str); + result = xstrprintf ("[%d] %s", numchild, str); + do_cleanups (old_chain); + } + else + result = xstrprintf ("[%d]", numchild); + + return result; +} + +/* Return a string representation of the (VALUE, TYPE) pair, using + the given print options OPTS as our formatting options. */ + +char * +ada_varobj_get_value_of_variable (struct value *value, + struct type *type, + struct value_print_options *opts) +{ + char *result = NULL; + + ada_varobj_decode_var (&value, &type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + result = xstrdup ("{...}"); + break; + case TYPE_CODE_ARRAY: + result = ada_varobj_get_value_of_array_variable (value, type, opts); + break; + default: + if (!value) + result = xstrdup (""); + else + result = ada_varobj_get_value_image (value, opts); + break; + } + + return result; +} + + diff --git a/contrib/gdb-7/gdb/ada-varobj.h b/contrib/gdb-7/gdb/ada-varobj.h new file mode 100644 index 0000000000..924997d3c4 --- /dev/null +++ b/contrib/gdb-7/gdb/ada-varobj.h @@ -0,0 +1,55 @@ +/* varobj support for Ada. + + Copyright (C) 2012-2013 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 ADA_VAROBJ_H +#define ADA_VAROBJ_H + +#include "varobj.h" + +struct value; +struct value_print_options; + +extern int ada_varobj_get_number_of_children (struct value *parent_value, + struct type *parent_type); + +extern char *ada_varobj_get_name_of_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + int child_index); + +extern char *ada_varobj_get_path_expr_of_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + const char *parent_path_expr, + int child_index); + +extern struct value *ada_varobj_get_value_of_child (struct value *parent_value, + struct type *parent_type, + const char *parent_name, + int child_index); + +extern struct type *ada_varobj_get_type_of_child (struct value *parent_value, + struct type *parent_type, + int child_index); + +extern char *ada_varobj_get_value_of_variable + (struct value *value, struct type *type, + struct value_print_options *opts); + +#endif /* ADA_VAROBJ_H */ diff --git a/contrib/gdb-7/gdb/addrmap.c b/contrib/gdb-7/gdb/addrmap.c index b06e4f62a1..22694ed8ce 100644 --- a/contrib/gdb-7/gdb/addrmap.c +++ b/contrib/gdb-7/gdb/addrmap.c @@ -1,6 +1,6 @@ /* addrmap.c --- implementation of address map data structure. - Copyright (C) 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2007-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/addrmap.h b/contrib/gdb-7/gdb/addrmap.h index 1552941d05..ee7c800e64 100644 --- a/contrib/gdb-7/gdb/addrmap.h +++ b/contrib/gdb-7/gdb/addrmap.h @@ -1,6 +1,6 @@ /* addrmap.h --- interface to address map data structure. - Copyright (C) 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2007-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/agent.c b/contrib/gdb-7/gdb/agent.c new file mode 100644 index 0000000000..63a0f327f7 --- /dev/null +++ b/contrib/gdb-7/gdb/agent.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2012-2013 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 "command.h" +#include "gdbcmd.h" +#include "target.h" +#include "agent.h" + +/* Enum strings for "set|show agent". */ + +static const char can_use_agent_on[] = "on"; +static const char can_use_agent_off[] = "off"; +static const char *can_use_agent_enum[] = +{ + can_use_agent_on, + can_use_agent_off, + NULL, +}; + +static const char *can_use_agent = can_use_agent_off; + +static void +show_can_use_agent (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, + _("Debugger's willingness to use agent in inferior " + "as a helper is %s.\n"), value); +} + +static void +set_can_use_agent (char *args, int from_tty, struct cmd_list_element *c) +{ + if (target_use_agent (can_use_agent == can_use_agent_on) == 0) + /* Something wrong during setting, set flag to default value. */ + can_use_agent = can_use_agent_off; +} + +/* -Wmissing-prototypes */ +extern initialize_file_ftype _initialize_agent; + +#include "observer.h" +#include "objfiles.h" + +static void +agent_new_objfile (struct objfile *objfile) +{ + if (objfile == NULL || agent_loaded_p ()) + return; + + agent_look_up_symbols (objfile); +} + +void +_initialize_agent (void) +{ + observer_attach_new_objfile (agent_new_objfile); + + add_setshow_enum_cmd ("agent", class_run, + can_use_agent_enum, + &can_use_agent, _("\ +Set debugger's willingness to use agent as a helper."), _("\ +Show debugger's willingness to use agent as a helper."), _("\ +If on, GDB will delegate some of the debugging operations to the\n\ +agent, if the target supports it. This will speed up those\n\ +operations that are supported by the agent.\n\ +If off, GDB will not use agent, even if such is supported by the\n\ +target."), + set_can_use_agent, + show_can_use_agent, + &setlist, &showlist); +} diff --git a/contrib/gdb-7/gdb/amd64-nat.c b/contrib/gdb-7/gdb/amd64-nat.c index 68654568a4..2a9239a58b 100644 --- a/contrib/gdb-7/gdb/amd64-nat.c +++ b/contrib/gdb-7/gdb/amd64-nat.c @@ -1,6 +1,6 @@ /* Native-dependent code for AMD64. - Copyright (C) 2003-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -59,7 +59,7 @@ amd64_native_gregset_reg_offset (struct gdbarch *gdbarch, int regnum) gdb_assert (regnum >= 0); - if (gdbarch_ptr_bit (gdbarch) == 32) + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) { reg_offset = amd64_native_gregset32_reg_offset; num_regs = amd64_native_gregset32_num_regs; @@ -96,7 +96,7 @@ amd64_supply_native_gregset (struct regcache *regcache, int num_regs = amd64_native_gregset64_num_regs; int i; - if (gdbarch_ptr_bit (gdbarch) == 32) + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) num_regs = amd64_native_gregset32_num_regs; if (num_regs > gdbarch_num_regs (gdbarch)) @@ -127,7 +127,7 @@ amd64_collect_native_gregset (const struct regcache *regcache, int num_regs = amd64_native_gregset64_num_regs; int i; - if (gdbarch_ptr_bit (gdbarch) == 32) + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) { num_regs = amd64_native_gregset32_num_regs; diff --git a/contrib/gdb-7/gdb/amd64-nat.h b/contrib/gdb-7/gdb/amd64-nat.h index a0f84885c3..58d37cd95f 100644 --- a/contrib/gdb-7/gdb/amd64-nat.h +++ b/contrib/gdb-7/gdb/amd64-nat.h @@ -1,6 +1,6 @@ /* Native-dependent code for AMD64. - Copyright (C) 2003-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/amd64-tdep.c b/contrib/gdb-7/gdb/amd64-tdep.c index ea65d0d55b..3ab74f035c 100644 --- a/contrib/gdb-7/gdb/amd64-tdep.c +++ b/contrib/gdb-7/gdb/amd64-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for AMD64. - Copyright (C) 2001-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. Contributed by Jiri Smid, SuSE Labs. @@ -43,6 +43,8 @@ #include "features/i386/amd64.c" #include "features/i386/amd64-avx.c" +#include "features/i386/x32.c" +#include "features/i386/x32-avx.c" #include "ax.h" #include "ax-gdb.h" @@ -256,7 +258,8 @@ static const char *amd64_word_names[] = static const char *amd64_dword_names[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp", - "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d", + "eip" }; /* Return the name of register REGNUM. */ @@ -443,12 +446,10 @@ amd64_non_pod_p (struct type *type) static void amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2]) { - int len = TYPE_LENGTH (type); - /* 1. If the size of an object is larger than two eightbytes, or in C++, is a non-POD structure or union type, or contains unaligned fields, it has class memory. */ - if (len > 16 || amd64_non_pod_p (type)) + if (TYPE_LENGTH (type) > 16 || amd64_non_pod_p (type)) { class[0] = class[1] = AMD64_MEMORY; return; @@ -468,7 +469,7 @@ amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2]) /* All fields in an array have the same type. */ amd64_classify (subtype, class); - if (len > 8 && class[1] == AMD64_NO_CLASS) + if (TYPE_LENGTH (type) > 8 && class[1] == AMD64_NO_CLASS) class[1] = class[0]; } else @@ -585,6 +586,23 @@ amd64_classify (struct type *type, enum amd64_reg_class class[2]) /* Class X87 and X87UP. */ class[0] = AMD64_X87, class[1] = AMD64_X87UP; + /* Arguments of complex T where T is one of the types float or + double get treated as if they are implemented as: + + struct complexT { + T real; + T imag; + }; */ + else if (code == TYPE_CODE_COMPLEX && len == 8) + class[0] = AMD64_SSE; + else if (code == TYPE_CODE_COMPLEX && len == 16) + class[0] = class[1] = AMD64_SSE; + + /* A variable of type complex long double is classified as type + COMPLEX_X87. */ + else if (code == TYPE_CODE_COMPLEX && len == 32) + class[0] = AMD64_COMPLEX_X87; + /* Aggregates. */ else if (code == TYPE_CODE_ARRAY || code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) @@ -592,7 +610,7 @@ amd64_classify (struct type *type, enum amd64_reg_class class[2]) } static enum return_value_convention -amd64_return_value (struct gdbarch *gdbarch, struct type *func_type, +amd64_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { @@ -635,6 +653,30 @@ amd64_return_value (struct gdbarch *gdbarch, struct type *func_type, return RETURN_VALUE_ABI_RETURNS_ADDRESS; } + /* 8. If the class is COMPLEX_X87, the real part of the value is + returned in %st0 and the imaginary part in %st1. */ + if (class[0] == AMD64_COMPLEX_X87) + { + if (readbuf) + { + regcache_raw_read (regcache, AMD64_ST0_REGNUM, readbuf); + regcache_raw_read (regcache, AMD64_ST1_REGNUM, readbuf + 16); + } + + if (writebuf) + { + i387_return_value (gdbarch, regcache); + regcache_raw_write (regcache, AMD64_ST0_REGNUM, writebuf); + regcache_raw_write (regcache, AMD64_ST1_REGNUM, writebuf + 16); + + /* Fix up the tag word such that both %st(0) and %st(1) are + marked as valid. */ + regcache_raw_write_unsigned (regcache, AMD64_FTAG_REGNUM, 0xfff); + } + + return RETURN_VALUE_REGISTER_CONVENTION; + } + gdb_assert (class[1] != AMD64_MEMORY); gdb_assert (len <= 16); @@ -836,10 +878,9 @@ amd64_push_arguments (struct regcache *regcache, int nargs, { struct type *type = value_type (stack_args[i]); const gdb_byte *valbuf = value_contents (stack_args[i]); - int len = TYPE_LENGTH (type); CORE_ADDR arg_addr = sp + element * 8; - write_memory (arg_addr, valbuf, len); + write_memory (arg_addr, valbuf, TYPE_LENGTH (type)); if (arg_addr_regno[i] >= 0) { /* We also need to store the address of that argument in @@ -850,7 +891,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs, store_unsigned_integer (buf, 8, byte_order, arg_addr); regcache_cooked_write (regcache, arg_addr_regno[i], buf); } - element += ((len + 7) / 8); + element += ((TYPE_LENGTH (type) + 7) / 8); } /* The psABI says that "For calls that may call functions that use @@ -1258,7 +1299,7 @@ amd64_displaced_step_copy_insn (struct gdbarch *gdbarch, struct regcache *regs) { int len = gdbarch_max_insn_length (gdbarch); - /* Extra space for sentinels so fixup_{riprel,displaced_copy don't have to + /* Extra space for sentinels so fixup_{riprel,displaced_copy} don't have to continually watch for running off the end of the buffer. */ int fixup_sentinel_space = len; struct displaced_step_closure *dsc = @@ -1590,7 +1631,7 @@ amd64_relocate_instruction (struct gdbarch *gdbarch, /* Where "ret" in the original code will return to. */ ret_addr = oldloc + insn_length; push_buf[0] = 0x68; /* pushq $... */ - memcpy (&push_buf[1], &ret_addr, 4); + store_unsigned_integer (&push_buf[1], 4, byte_order, ret_addr); /* Push the push. */ append_insns (to, 5, push_buf); @@ -1858,6 +1899,188 @@ amd64_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc, return min (pc + offset + 2, current_pc); } +/* Similar to amd64_analyze_stack_align for x32. */ + +static CORE_ADDR +amd64_x32_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc, + struct amd64_frame_cache *cache) +{ + /* There are 2 code sequences to re-align stack before the frame + gets set up: + + 1. Use a caller-saved saved register: + + leaq 8(%rsp), %reg + andq $-XXX, %rsp + pushq -8(%reg) + + or + + [addr32] leal 8(%rsp), %reg + andl $-XXX, %esp + [addr32] pushq -8(%reg) + + 2. Use a callee-saved saved register: + + pushq %reg + leaq 16(%rsp), %reg + andq $-XXX, %rsp + pushq -8(%reg) + + or + + pushq %reg + [addr32] leal 16(%rsp), %reg + andl $-XXX, %esp + [addr32] pushq -8(%reg) + + "andq $-XXX, %rsp" can be either 4 bytes or 7 bytes: + + 0x48 0x83 0xe4 0xf0 andq $-16, %rsp + 0x48 0x81 0xe4 0x00 0xff 0xff 0xff andq $-256, %rsp + + "andl $-XXX, %esp" can be either 3 bytes or 6 bytes: + + 0x83 0xe4 0xf0 andl $-16, %esp + 0x81 0xe4 0x00 0xff 0xff 0xff andl $-256, %esp + */ + + gdb_byte buf[19]; + int reg, r; + int offset, offset_and; + + if (target_read_memory (pc, buf, sizeof buf)) + return pc; + + /* Skip optional addr32 prefix. */ + offset = buf[0] == 0x67 ? 1 : 0; + + /* Check caller-saved saved register. The first instruction has + to be "leaq 8(%rsp), %reg" or "leal 8(%rsp), %reg". */ + if (((buf[offset] & 0xfb) == 0x48 || (buf[offset] & 0xfb) == 0x40) + && buf[offset + 1] == 0x8d + && buf[offset + 3] == 0x24 + && buf[offset + 4] == 0x8) + { + /* MOD must be binary 10 and R/M must be binary 100. */ + if ((buf[offset + 2] & 0xc7) != 0x44) + return pc; + + /* REG has register number. */ + reg = (buf[offset + 2] >> 3) & 7; + + /* Check the REX.R bit. */ + if ((buf[offset] & 0x4) != 0) + reg += 8; + + offset += 5; + } + else + { + /* Check callee-saved saved register. The first instruction + has to be "pushq %reg". */ + reg = 0; + if ((buf[offset] & 0xf6) == 0x40 + && (buf[offset + 1] & 0xf8) == 0x50) + { + /* Check the REX.B bit. */ + if ((buf[offset] & 1) != 0) + reg = 8; + + offset += 1; + } + else if ((buf[offset] & 0xf8) != 0x50) + return pc; + + /* Get register. */ + reg += buf[offset] & 0x7; + + offset++; + + /* Skip optional addr32 prefix. */ + if (buf[offset] == 0x67) + offset++; + + /* The next instruction has to be "leaq 16(%rsp), %reg" or + "leal 16(%rsp), %reg". */ + if (((buf[offset] & 0xfb) != 0x48 && (buf[offset] & 0xfb) != 0x40) + || buf[offset + 1] != 0x8d + || buf[offset + 3] != 0x24 + || buf[offset + 4] != 0x10) + return pc; + + /* MOD must be binary 10 and R/M must be binary 100. */ + if ((buf[offset + 2] & 0xc7) != 0x44) + return pc; + + /* REG has register number. */ + r = (buf[offset + 2] >> 3) & 7; + + /* Check the REX.R bit. */ + if ((buf[offset] & 0x4) != 0) + r += 8; + + /* Registers in pushq and leaq have to be the same. */ + if (reg != r) + return pc; + + offset += 5; + } + + /* Rigister can't be %rsp nor %rbp. */ + if (reg == 4 || reg == 5) + return pc; + + /* The next instruction may be "andq $-XXX, %rsp" or + "andl $-XXX, %esp". */ + if (buf[offset] != 0x48) + offset--; + + if (buf[offset + 2] != 0xe4 + || (buf[offset + 1] != 0x81 && buf[offset + 1] != 0x83)) + return pc; + + offset_and = offset; + offset += buf[offset + 1] == 0x81 ? 7 : 4; + + /* Skip optional addr32 prefix. */ + if (buf[offset] == 0x67) + offset++; + + /* The next instruction has to be "pushq -8(%reg)". */ + r = 0; + if (buf[offset] == 0xff) + offset++; + else if ((buf[offset] & 0xf6) == 0x40 + && buf[offset + 1] == 0xff) + { + /* Check the REX.B bit. */ + if ((buf[offset] & 0x1) != 0) + r = 8; + offset += 2; + } + else + return pc; + + /* 8bit -8 is 0xf8. REG must be binary 110 and MOD must be binary + 01. */ + if (buf[offset + 1] != 0xf8 + || (buf[offset] & 0xf8) != 0x70) + return pc; + + /* R/M has register. */ + r += buf[offset] & 7; + + /* Registers in leaq and pushq have to be the same. */ + if (reg != r) + return pc; + + if (current_pc > pc + offset_and) + cache->saved_sp_reg = amd64_arch_reg_to_regnum (reg); + + return min (pc + offset + 2, current_pc); +} + /* Do a limited analysis of the prologue at PC and update CACHE accordingly. Bail out early if CURRENT_PC is reached. Return the address where the analysis stopped. @@ -1865,10 +2088,16 @@ amd64_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc, We will handle only functions beginning with: pushq %rbp 0x55 - movq %rsp, %rbp 0x48 0x89 0xe5 + movq %rsp, %rbp 0x48 0x89 0xe5 (or 0x48 0x8b 0xec) + + or (for the X32 ABI): + + pushq %rbp 0x55 + movl %esp, %ebp 0x89 0xe5 (or 0x8b 0xec) - Any function that doesn't start with this sequence will be assumed - to have no prologue and thus no valid frame pointer in %rbp. */ + Any function that doesn't start with one of these sequences will be + assumed to have no prologue and thus no valid frame pointer in + %rbp. */ static CORE_ADDR amd64_analyze_prologue (struct gdbarch *gdbarch, @@ -1876,14 +2105,23 @@ amd64_analyze_prologue (struct gdbarch *gdbarch, struct amd64_frame_cache *cache) { enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - static gdb_byte proto[3] = { 0x48, 0x89, 0xe5 }; /* movq %rsp, %rbp */ + /* There are two variations of movq %rsp, %rbp. */ + static const gdb_byte mov_rsp_rbp_1[3] = { 0x48, 0x89, 0xe5 }; + static const gdb_byte mov_rsp_rbp_2[3] = { 0x48, 0x8b, 0xec }; + /* Ditto for movl %esp, %ebp. */ + static const gdb_byte mov_esp_ebp_1[2] = { 0x89, 0xe5 }; + static const gdb_byte mov_esp_ebp_2[2] = { 0x8b, 0xec }; + gdb_byte buf[3]; gdb_byte op; if (current_pc <= pc) return current_pc; - pc = amd64_analyze_stack_align (pc, current_pc, cache); + if (gdbarch_ptr_bit (gdbarch) == 32) + pc = amd64_x32_analyze_stack_align (pc, current_pc, cache); + else + pc = amd64_analyze_stack_align (pc, current_pc, cache); op = read_memory_unsigned_integer (pc, 1, byte_order); @@ -1898,14 +2136,30 @@ amd64_analyze_prologue (struct gdbarch *gdbarch, if (current_pc <= pc + 1) return current_pc; - /* Check for `movq %rsp, %rbp'. */ read_memory (pc + 1, buf, 3); - if (memcmp (buf, proto, 3) != 0) - return pc + 1; - /* OK, we actually have a frame. */ - cache->frameless_p = 0; - return pc + 4; + /* Check for `movq %rsp, %rbp'. */ + if (memcmp (buf, mov_rsp_rbp_1, 3) == 0 + || memcmp (buf, mov_rsp_rbp_2, 3) == 0) + { + /* OK, we actually have a frame. */ + cache->frameless_p = 0; + return pc + 4; + } + + /* For X32, also check for `movq %esp, %ebp'. */ + if (gdbarch_ptr_bit (gdbarch) == 32) + { + if (memcmp (buf, mov_esp_ebp_1, 2) == 0 + || memcmp (buf, mov_esp_ebp_2, 2) == 0) + { + /* OK, we actually have a frame. */ + cache->frameless_p = 0; + return pc + 3; + } + } + + return pc + 1; } return pc; @@ -1998,6 +2252,22 @@ amd64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) { struct amd64_frame_cache cache; CORE_ADDR pc; + CORE_ADDR func_addr; + + if (find_pc_partial_function (start_pc, NULL, &func_addr, NULL)) + { + CORE_ADDR post_prologue_pc + = skip_prologue_using_sal (gdbarch, func_addr); + struct symtab *s = find_pc_symtab (func_addr); + + /* Clang always emits a line note before the prologue and another + one after. We trust clang to emit usable line notes. */ + if (post_prologue_pc + && (s != NULL + && s->producer != NULL + && strncmp (s->producer, "clang ", sizeof ("clang ") - 1) == 0)) + return max (start_pc, post_prologue_pc); + } amd64_init_frame_cache (&cache); pc = amd64_analyze_prologue (gdbarch, start_pc, 0xffffffffffffffffLL, @@ -2688,6 +2958,53 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_relocate_instruction (gdbarch, amd64_relocate_instruction); set_gdbarch_gen_return_address (gdbarch, amd64_gen_return_address); + + /* SystemTap variables and functions. */ + set_gdbarch_stap_integer_prefix (gdbarch, "$"); + set_gdbarch_stap_register_prefix (gdbarch, "%"); + set_gdbarch_stap_register_indirection_prefix (gdbarch, "("); + set_gdbarch_stap_register_indirection_suffix (gdbarch, ")"); + set_gdbarch_stap_is_single_operand (gdbarch, + i386_stap_is_single_operand); + set_gdbarch_stap_parse_special_token (gdbarch, + i386_stap_parse_special_token); +} + + +static struct type * +amd64_x32_pseudo_register_type (struct gdbarch *gdbarch, int regnum) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + switch (regnum - tdep->eax_regnum) + { + case AMD64_RBP_REGNUM: /* %ebp */ + case AMD64_RSP_REGNUM: /* %esp */ + return builtin_type (gdbarch)->builtin_data_ptr; + case AMD64_RIP_REGNUM: /* %eip */ + return builtin_type (gdbarch)->builtin_func_ptr; + } + + return i386_pseudo_register_type (gdbarch, regnum); +} + +void +amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + const struct target_desc *tdesc = info.target_desc; + + amd64_init_abi (info, gdbarch); + + if (! tdesc_has_registers (tdesc)) + tdesc = tdesc_x32; + tdep->tdesc = tdesc; + + tdep->num_dword_regs = 17; + set_tdesc_pseudo_register_type (gdbarch, amd64_x32_pseudo_register_type); + + set_gdbarch_long_bit (gdbarch, 32); + set_gdbarch_ptr_bit (gdbarch, 32); } /* Provide a prototype to silence -Wmissing-prototypes. */ @@ -2698,6 +3015,8 @@ _initialize_amd64_tdep (void) { initialize_tdesc_amd64 (); initialize_tdesc_amd64_avx (); + initialize_tdesc_x32 (); + initialize_tdesc_x32_avx (); } @@ -2722,7 +3041,8 @@ amd64_supply_fxsave (struct regcache *regcache, int regnum, i387_supply_fxsave (regcache, regnum, fxsave); - if (fxsave && gdbarch_ptr_bit (gdbarch) == 64) + if (fxsave + && gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64) { const gdb_byte *regs = fxsave; @@ -2744,7 +3064,8 @@ amd64_supply_xsave (struct regcache *regcache, int regnum, i387_supply_xsave (regcache, regnum, xsave); - if (xsave && gdbarch_ptr_bit (gdbarch) == 64) + if (xsave + && gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64) { const gdb_byte *regs = xsave; @@ -2772,7 +3093,7 @@ amd64_collect_fxsave (const struct regcache *regcache, int regnum, i387_collect_fxsave (regcache, regnum, fxsave); - if (gdbarch_ptr_bit (gdbarch) == 64) + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64) { if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep)) regcache_raw_collect (regcache, I387_FISEG_REGNUM (tdep), regs + 12); @@ -2793,7 +3114,7 @@ amd64_collect_xsave (const struct regcache *regcache, int regnum, i387_collect_xsave (regcache, regnum, xsave, gcore); - if (gdbarch_ptr_bit (gdbarch) == 64) + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64) { if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep)) regcache_raw_collect (regcache, I387_FISEG_REGNUM (tdep), diff --git a/contrib/gdb-7/gdb/amd64-tdep.h b/contrib/gdb-7/gdb/amd64-tdep.h index 1ed109cdd0..a33e7d6a45 100644 --- a/contrib/gdb-7/gdb/amd64-tdep.h +++ b/contrib/gdb-7/gdb/amd64-tdep.h @@ -1,7 +1,6 @@ /* Target-dependent definitions for AMD64. - Copyright (C) 2001, 2003-2004, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. Contributed by Jiri Smid, SuSE Labs. This file is part of GDB. @@ -57,8 +56,10 @@ enum amd64_regnum AMD64_FS_REGNUM, /* %fs */ AMD64_GS_REGNUM, /* %gs */ AMD64_ST0_REGNUM = 24, /* %st0 */ + AMD64_ST1_REGNUM, /* %st1 */ AMD64_FCTRL_REGNUM = AMD64_ST0_REGNUM + 8, AMD64_FSTAT_REGNUM = AMD64_ST0_REGNUM + 9, + AMD64_FTAG_REGNUM = AMD64_ST0_REGNUM + 10, AMD64_XMM0_REGNUM = 40, /* %xmm0 */ AMD64_XMM1_REGNUM, /* %xmm1 */ AMD64_MXCSR_REGNUM = AMD64_XMM0_REGNUM + 16, @@ -80,6 +81,8 @@ extern void amd64_displaced_step_fixup (struct gdbarch *gdbarch, struct regcache *regs); extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch); +extern void amd64_x32_init_abi (struct gdbarch_info info, + struct gdbarch *gdbarch); /* Fill register REGNUM in REGCACHE with the appropriate floating-point or SSE register value from *FXSAVE. If REGNUM is diff --git a/contrib/gdb-7/gdb/amd64bsd-nat.c b/contrib/gdb-7/gdb/amd64bsd-nat.c index b7283e9f61..1cd9207486 100644 --- a/contrib/gdb-7/gdb/amd64bsd-nat.c +++ b/contrib/gdb-7/gdb/amd64bsd-nat.c @@ -1,6 +1,6 @@ /* Native-dependent code for AMD64 BSD's. - Copyright (C) 2003-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -32,6 +32,7 @@ #include "amd64-tdep.h" #include "amd64-nat.h" +#include "amd64bsd-nat.h" #include "inf-ptrace.h" @@ -125,3 +126,75 @@ amd64bsd_target (void) t->to_store_registers = amd64bsd_store_inferior_registers; return t; } + + +/* Support for debug registers. */ + +#ifdef HAVE_PT_GETDBREGS + +static unsigned long +amd64bsd_dr_get (ptid_t ptid, int regnum) +{ + struct dbreg dbregs; + + if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid), + (PTRACE_TYPE_ARG3) &dbregs, 0) == -1) + perror_with_name (_("Couldn't read debug registers")); + + return DBREG_DRX ((&dbregs), regnum); +} + +static void +amd64bsd_dr_set (int regnum, unsigned long value) +{ + struct dbreg dbregs; + + if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid), + (PTRACE_TYPE_ARG3) &dbregs, 0) == -1) + perror_with_name (_("Couldn't get debug registers")); + + /* For some mysterious reason, some of the reserved bits in the + debug control register get set. Mask these off, otherwise the + ptrace call below will fail. */ + DBREG_DRX ((&dbregs), 7) &= ~(0xffffffff0000fc00); + + DBREG_DRX ((&dbregs), regnum) = value; + + if (ptrace (PT_SETDBREGS, PIDGET (inferior_ptid), + (PTRACE_TYPE_ARG3) &dbregs, 0) == -1) + perror_with_name (_("Couldn't write debug registers")); +} + +void +amd64bsd_dr_set_control (unsigned long control) +{ + amd64bsd_dr_set (7, control); +} + +void +amd64bsd_dr_set_addr (int regnum, CORE_ADDR addr) +{ + gdb_assert (regnum >= 0 && regnum <= 4); + + amd64bsd_dr_set (regnum, addr); +} + +CORE_ADDR +amd64bsd_dr_get_addr (int regnum) +{ + return amd64bsd_dr_get (inferior_ptid, regnum); +} + +unsigned long +amd64bsd_dr_get_status (void) +{ + return amd64bsd_dr_get (inferior_ptid, 6); +} + +unsigned long +amd64bsd_dr_get_control (void) +{ + return amd64bsd_dr_get (inferior_ptid, 7); +} + +#endif /* PT_GETDBREGS */ diff --git a/contrib/gdb-7/gdb/gdb_select.h b/contrib/gdb-7/gdb/amd64bsd-nat.h similarity index 57% copy from contrib/gdb-7/gdb/gdb_select.h copy to contrib/gdb-7/gdb/amd64bsd-nat.h index e55ae2297c..d9d9bb2b4c 100644 --- a/contrib/gdb-7/gdb/gdb_select.h +++ b/contrib/gdb-7/gdb/amd64bsd-nat.h @@ -1,6 +1,6 @@ -/* Slightly more portable version of . +/* Native-dependent code for AMD64 BSD's. - Copyright (C) 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,20 +17,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#if !defined(GDB_SELECT_H) -#define GDB_SELECT_H +#ifndef AMD64BSD_NAT_H +#define AMD64BSD_NAT_H -#ifdef HAVE_SYS_SELECT_H -#include -#else -#include -#endif +/* Low level amd64 debug register functions. */ -#ifdef USE_WIN32API -#include -#endif +extern void amd64bsd_dr_set_control (unsigned long control); -extern int gdb_select (int n, fd_set *readfds, fd_set *writefds, - fd_set *exceptfds, struct timeval *timeout); +extern void amd64bsd_dr_set_addr (int regnum, CORE_ADDR addr); -#endif /* !defined(GDB_SELECT_H) */ +extern CORE_ADDR amd64bsd_dr_get_addr (int regnum); + +extern unsigned long amd64bsd_dr_get_status (void); + +extern unsigned long amd64bsd_dr_get_control (void); + +#endif /* amd64bsd-nat.h */ diff --git a/contrib/gdb-7/gdb/annotate.c b/contrib/gdb-7/gdb/annotate.c index cd0a94aeda..ccba5fe67a 100644 --- a/contrib/gdb-7/gdb/annotate.c +++ b/contrib/gdb-7/gdb/annotate.c @@ -1,6 +1,5 @@ /* Annotation routines for GDB. - Copyright (C) 1986, 1989-1992, 1994-1996, 1998-2000, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -24,6 +23,7 @@ #include "gdbtypes.h" #include "breakpoint.h" #include "observer.h" +#include "inferior.h" /* Prototypes for local functions. */ @@ -38,7 +38,22 @@ static void breakpoint_changed (struct breakpoint *b); void (*deprecated_annotate_signalled_hook) (void); void (*deprecated_annotate_signal_hook) (void); -static int ignore_count_changed = 0; +/* Booleans indicating whether we've emitted certain notifications. + Used to suppress useless repeated notifications until the next time + we're ready to accept more commands. Reset whenever a prompt is + displayed. */ +static int frames_invalid_emitted; +static int breakpoints_invalid_emitted; + +/* True if the target can async, and a synchronous execution command + is not in progress. If true, input is accepted, so don't suppress + annotations. */ + +static int +async_background_execution_p (void) +{ + return (target_can_async_p () && !sync_execution); +} static void print_value_flags (struct type *t) @@ -48,32 +63,20 @@ print_value_flags (struct type *t) else printf_filtered (("-")); } - -void -breakpoints_changed (void) + +static void +annotate_breakpoints_invalid (void) { - if (annotation_level == 2) + if (annotation_level == 2 + && (!breakpoints_invalid_emitted + || async_background_execution_p ())) { target_terminal_ours (); printf_unfiltered (("\n\032\032breakpoints-invalid\n")); - if (ignore_count_changed) - ignore_count_changed = 0; /* Avoid multiple break annotations. */ + breakpoints_invalid_emitted = 1; } } -/* The GUI needs to be informed of ignore_count changes, but we don't - want to provide successive multiple breakpoints-invalid messages - that are all caused by the fact that the ignore count is changing - (which could keep the GUI very busy). One is enough, after the - target actually "stops". */ - -void -annotate_ignore_count_change (void) -{ - if (annotation_level > 1) - ignore_count_changed = 1; -} - void annotate_breakpoint (int num) { @@ -107,11 +110,6 @@ annotate_stopped (void) { if (annotation_level > 1) printf_filtered (("\n\032\032stopped\n")); - if (annotation_level > 1 && ignore_count_changed) - { - ignore_count_changed = 0; - breakpoints_changed (); - } } void @@ -207,10 +205,13 @@ annotate_breakpoints_table_end (void) void annotate_frames_invalid (void) { - if (annotation_level == 2) + if (annotation_level == 2 + && (!frames_invalid_emitted + || async_background_execution_p ())) { target_terminal_ours (); printf_unfiltered (("\n\032\032frames-invalid\n")); + frames_invalid_emitted = 1; } } @@ -560,18 +561,30 @@ annotate_array_section_end (void) printf_filtered (("\n\032\032array-section-end\n")); } +/* Called when GDB is about to display the prompt. Used to reset + annotation suppression whenever we're ready to accept new + frontend/user commands. */ + +void +annotate_display_prompt (void) +{ + frames_invalid_emitted = 0; + breakpoints_invalid_emitted = 0; +} + static void breakpoint_changed (struct breakpoint *b) { - breakpoints_changed (); + if (b->number <= 0) + return; + + annotate_breakpoints_invalid (); } void _initialize_annotate (void) { - if (annotation_level == 2) - { - observer_attach_breakpoint_deleted (breakpoint_changed); - observer_attach_breakpoint_modified (breakpoint_changed); - } + observer_attach_breakpoint_created (breakpoint_changed); + observer_attach_breakpoint_deleted (breakpoint_changed); + observer_attach_breakpoint_modified (breakpoint_changed); } diff --git a/contrib/gdb-7/gdb/annotate.h b/contrib/gdb-7/gdb/annotate.h index 0eae524870..72c4f19dda 100644 --- a/contrib/gdb-7/gdb/annotate.h +++ b/contrib/gdb-7/gdb/annotate.h @@ -1,6 +1,5 @@ /* Annotation routines for GDB. - Copyright (C) 1986, 1989-1992, 1994, 1998-2000, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -20,9 +19,6 @@ #include "symtab.h" #include "gdbtypes.h" -extern void breakpoints_changed (void); - -extern void annotate_ignore_count_change (void); extern void annotate_breakpoint (int); extern void annotate_catchpoint (int); extern void annotate_watchpoint (int); @@ -46,6 +42,8 @@ extern void annotate_frames_invalid (void); extern void annotate_new_thread (void); extern void annotate_thread_changed (void); +extern void annotate_display_prompt (void); + struct type; extern void annotate_field_begin (struct type *); diff --git a/contrib/gdb-7/gdb/arch-utils.c b/contrib/gdb-7/gdb/arch-utils.c index 45dccad059..42802a018e 100644 --- a/contrib/gdb-7/gdb/arch-utils.c +++ b/contrib/gdb-7/gdb/arch-utils.c @@ -1,6 +1,6 @@ /* Dynamic architecture support for GDB, the GNU debugger. - Copyright (C) 1998-2012 Free Software Foundation, Inc. + Copyright (C) 1998-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -31,6 +31,7 @@ #include "osabi.h" #include "target-descriptions.h" #include "objfiles.h" +#include "language.h" #include "version.h" @@ -120,7 +121,7 @@ generic_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) int generic_in_solib_return_trampoline (struct gdbarch *gdbarch, - CORE_ADDR pc, char *name) + CORE_ADDR pc, const char *name) { return 0; } @@ -251,7 +252,7 @@ static int target_byte_order_user = BFD_ENDIAN_UNKNOWN; static const char endian_big[] = "big"; static const char endian_little[] = "little"; static const char endian_auto[] = "auto"; -static const char *endian_enum[] = +static const char *const endian_enum[] = { endian_big, endian_little, @@ -505,7 +506,7 @@ gdbarch_update_p (struct gdbarch_info info) /* If it is the same old architecture, accept the request (but don't swap anything). */ - if (new_gdbarch == target_gdbarch) + if (new_gdbarch == target_gdbarch ()) { if (gdbarch_debug) fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: " @@ -521,7 +522,7 @@ gdbarch_update_p (struct gdbarch_info info) "New architecture %s (%s) selected\n", host_address_to_string (new_gdbarch), gdbarch_bfd_arch_info (new_gdbarch)->printable_name); - deprecated_target_gdbarch_select_hack (new_gdbarch); + set_target_gdbarch (new_gdbarch); return 1; } @@ -555,7 +556,7 @@ set_gdbarch_from_file (bfd *abfd) if (gdbarch == NULL) error (_("Architecture of file not recognized.")); - deprecated_target_gdbarch_select_hack (gdbarch); + set_target_gdbarch (gdbarch); } /* Initialize the current architecture. Update the ``set @@ -756,7 +757,7 @@ get_current_arch (void) if (has_stack_frames ()) return get_frame_arch (get_selected_frame (NULL)); else - return target_gdbarch; + return target_gdbarch (); } int @@ -793,6 +794,16 @@ default_gen_return_address (struct gdbarch *gdbarch, error (_("This architecture has no method to collect a return address.")); } +int +default_return_in_first_hidden_param_p (struct gdbarch *gdbarch, + struct type *type) +{ + /* Usually, the return value's address is stored the in the "first hidden" + parameter if the return value should be passed by reference, as + specified in ABI. */ + return language_pass_by_reference (type); +} + /* */ /* -Wmissing-prototypes */ diff --git a/contrib/gdb-7/gdb/arch-utils.h b/contrib/gdb-7/gdb/arch-utils.h index 45ddf6483b..3f0e64fe68 100644 --- a/contrib/gdb-7/gdb/arch-utils.h +++ b/contrib/gdb-7/gdb/arch-utils.h @@ -1,7 +1,6 @@ /* Dynamic architecture support for GDB, the GNU debugger. - Copyright (C) 1998-2000, 2002-2004, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1998-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -27,9 +26,6 @@ struct minimal_symbol; struct type; struct gdbarch_info; -/* gdbarch trace variable */ -extern int gdbarch_debug; - /* An implementation of gdbarch_displaced_step_copy_insn for processors that don't need to modify the instruction before single-stepping the displaced copy. @@ -99,7 +95,7 @@ extern CORE_ADDR generic_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc); extern int generic_in_solib_return_trampoline (struct gdbarch *gdbarch, - CORE_ADDR pc, char *name); + CORE_ADDR pc, const char *name); extern int generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc); @@ -172,4 +168,6 @@ extern void default_gen_return_address (struct gdbarch *gdbarch, extern const char *default_auto_charset (void); extern const char *default_auto_wide_charset (void); +extern int default_return_in_first_hidden_param_p (struct gdbarch *, + struct type *); #endif diff --git a/contrib/gdb-7/gdb/auto-load.c b/contrib/gdb-7/gdb/auto-load.c new file mode 100644 index 0000000000..b12995b652 --- /dev/null +++ b/contrib/gdb-7/gdb/auto-load.c @@ -0,0 +1,1306 @@ +/* GDB routines for supporting auto-loaded scripts. + + Copyright (C) 2012-2013 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 "auto-load.h" +#include "progspace.h" +#include "python/python.h" +#include "gdb_regex.h" +#include "ui-out.h" +#include "filenames.h" +#include "command.h" +#include "observer.h" +#include "objfiles.h" +#include "exceptions.h" +#include "cli/cli-script.h" +#include "gdbcmd.h" +#include "cli/cli-decode.h" +#include "cli/cli-setshow.h" +#include "gdb_vecs.h" +#include "readline/tilde.h" +#include "completer.h" +#include "observer.h" +#include "fnmatch.h" +#include "top.h" + +/* The suffix of per-objfile scripts to auto-load as non-Python command files. + E.g. When the program loads libfoo.so, look for libfoo-gdb.gdb. */ +#define GDB_AUTO_FILE_NAME "-gdb.gdb" + +static void source_gdb_script_for_objfile (struct objfile *objfile, FILE *file, + const char *filename); + +/* Value of the 'set debug auto-load' configuration variable. */ +static int debug_auto_load = 0; + +/* "show" command for the debug_auto_load configuration variable. */ + +static void +show_debug_auto_load (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Debugging output for files " + "of 'set auto-load ...' is %s.\n"), + value); +} + +/* User-settable option to enable/disable auto-loading of GDB_AUTO_FILE_NAME + scripts: + set auto-load gdb-scripts on|off + This is true if we should auto-load associated scripts when an objfile + is opened, false otherwise. */ +static int auto_load_gdb_scripts = 1; + +/* "show" command for the auto_load_gdb_scripts configuration variable. */ + +static void +show_auto_load_gdb_scripts (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Auto-loading of canned sequences of commands " + "scripts is %s.\n"), + value); +} + +/* Internal-use flag to enable/disable auto-loading. + This is true if we should auto-load python code when an objfile is opened, + false otherwise. + + Both auto_load_scripts && global_auto_load must be true to enable + auto-loading. + + This flag exists to facilitate deferring auto-loading during start-up + until after ./.gdbinit has been read; it may augment the search directories + used to find the scripts. */ +int global_auto_load = 1; + +/* Auto-load .gdbinit file from the current directory? */ +int auto_load_local_gdbinit = 1; + +/* Absolute pathname to the current directory .gdbinit, if it exists. */ +char *auto_load_local_gdbinit_pathname = NULL; + +/* Boolean value if AUTO_LOAD_LOCAL_GDBINIT_PATHNAME has been loaded. */ +int auto_load_local_gdbinit_loaded = 0; + +/* "show" command for the auto_load_local_gdbinit configuration variable. */ + +static void +show_auto_load_local_gdbinit (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Auto-loading of .gdbinit script from current " + "directory is %s.\n"), + value); +} + +/* Directory list from which to load auto-loaded scripts. It is not checked + for absolute paths but they are strongly recommended. It is initialized by + _initialize_auto_load. */ +static char *auto_load_dir; + +/* "set" command for the auto_load_dir configuration variable. */ + +static void +set_auto_load_dir (char *args, int from_tty, struct cmd_list_element *c) +{ + /* Setting the variable to "" resets it to the compile time defaults. */ + if (auto_load_dir[0] == '\0') + { + xfree (auto_load_dir); + auto_load_dir = xstrdup (AUTO_LOAD_DIR); + } +} + +/* "show" command for the auto_load_dir configuration variable. */ + +static void +show_auto_load_dir (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("List of directories from which to load " + "auto-loaded scripts is %s.\n"), + value); +} + +/* Directory list safe to hold auto-loaded files. It is not checked for + absolute paths but they are strongly recommended. It is initialized by + _initialize_auto_load. */ +static char *auto_load_safe_path; + +/* Vector of directory elements of AUTO_LOAD_SAFE_PATH with each one normalized + by tilde_expand and possibly each entries has added its gdb_realpath + counterpart. */ +static VEC (char_ptr) *auto_load_safe_path_vec; + +/* Expand $datadir and $debugdir in STRING according to the rules of + substitute_path_component. Return vector from dirnames_to_char_ptr_vec, + this vector must be freed by free_char_ptr_vec by the caller. */ + +static VEC (char_ptr) * +auto_load_expand_dir_vars (const char *string) +{ + VEC (char_ptr) *dir_vec; + char *s; + + s = xstrdup (string); + substitute_path_component (&s, "$datadir", gdb_datadir); + substitute_path_component (&s, "$debugdir", debug_file_directory); + + if (debug_auto_load && strcmp (s, string) != 0) + fprintf_unfiltered (gdb_stdlog, + _("auto-load: Expanded $-variables to \"%s\".\n"), s); + + dir_vec = dirnames_to_char_ptr_vec (s); + xfree(s); + + return dir_vec; +} + +/* Update auto_load_safe_path_vec from current AUTO_LOAD_SAFE_PATH. */ + +static void +auto_load_safe_path_vec_update (void) +{ + unsigned len; + int ix; + + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, + _("auto-load: Updating directories of \"%s\".\n"), + auto_load_safe_path); + + free_char_ptr_vec (auto_load_safe_path_vec); + + auto_load_safe_path_vec = auto_load_expand_dir_vars (auto_load_safe_path); + len = VEC_length (char_ptr, auto_load_safe_path_vec); + + /* Apply tilde_expand and gdb_realpath to each AUTO_LOAD_SAFE_PATH_VEC + element. */ + for (ix = 0; ix < len; ix++) + { + char *dir = VEC_index (char_ptr, auto_load_safe_path_vec, ix); + char *expanded = tilde_expand (dir); + char *real_path = gdb_realpath (expanded); + + /* Ensure the current entry is at least tilde_expand-ed. */ + VEC_replace (char_ptr, auto_load_safe_path_vec, ix, expanded); + + if (debug_auto_load) + { + if (strcmp (expanded, dir) == 0) + fprintf_unfiltered (gdb_stdlog, + _("auto-load: Using directory \"%s\".\n"), + expanded); + else + fprintf_unfiltered (gdb_stdlog, + _("auto-load: Resolved directory \"%s\" " + "as \"%s\".\n"), + dir, expanded); + } + xfree (dir); + + /* If gdb_realpath returns a different content, append it. */ + if (strcmp (real_path, expanded) == 0) + xfree (real_path); + else + { + VEC_safe_push (char_ptr, auto_load_safe_path_vec, real_path); + + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, + _("auto-load: And canonicalized as \"%s\".\n"), + real_path); + } + } +} + +/* Variable gdb_datadir has been set. Update content depending on $datadir. */ + +static void +auto_load_gdb_datadir_changed (void) +{ + auto_load_safe_path_vec_update (); +} + +/* "set" command for the auto_load_safe_path configuration variable. */ + +static void +set_auto_load_safe_path (char *args, int from_tty, struct cmd_list_element *c) +{ + /* Setting the variable to "" resets it to the compile time defaults. */ + if (auto_load_safe_path[0] == '\0') + { + xfree (auto_load_safe_path); + auto_load_safe_path = xstrdup (AUTO_LOAD_SAFE_PATH); + } + + auto_load_safe_path_vec_update (); +} + +/* "show" command for the auto_load_safe_path configuration variable. */ + +static void +show_auto_load_safe_path (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + const char *cs; + + /* Check if user has entered either "/" or for example ":". + But while more complicate content like ":/foo" would still also + permit any location do not hide those. */ + + for (cs = value; *cs && (*cs == DIRNAME_SEPARATOR || IS_DIR_SEPARATOR (*cs)); + cs++); + if (*cs == 0) + fprintf_filtered (file, _("Auto-load files are safe to load from any " + "directory.\n")); + else + fprintf_filtered (file, _("List of directories from which it is safe to " + "auto-load files is %s.\n"), + value); +} + +/* "add-auto-load-safe-path" command for the auto_load_safe_path configuration + variable. */ + +static void +add_auto_load_safe_path (char *args, int from_tty) +{ + char *s; + + if (args == NULL || *args == 0) + error (_("\ +Directory argument required.\n\ +Use 'set auto-load safe-path /' for disabling the auto-load safe-path security.\ +")); + + s = xstrprintf ("%s%c%s", auto_load_safe_path, DIRNAME_SEPARATOR, args); + xfree (auto_load_safe_path); + auto_load_safe_path = s; + + auto_load_safe_path_vec_update (); +} + +/* Implementation for filename_is_in_pattern overwriting the caller's FILENAME + and PATTERN. */ + +static int +filename_is_in_pattern_1 (char *filename, char *pattern) +{ + size_t pattern_len = strlen (pattern); + size_t filename_len = strlen (filename); + + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, _("auto-load: Matching file \"%s\" " + "to pattern \"%s\"\n"), + filename, pattern); + + /* Trim trailing slashes ("/") from PATTERN. Even for "d:\" paths as + trailing slashes are trimmed also from FILENAME it still matches + correctly. */ + while (pattern_len && IS_DIR_SEPARATOR (pattern[pattern_len - 1])) + pattern_len--; + pattern[pattern_len] = '\0'; + + /* Ensure auto_load_safe_path "/" matches any FILENAME. On MS-Windows + platform FILENAME even after gdb_realpath does not have to start with + IS_DIR_SEPARATOR character, such as the 'C:\x.exe' filename. */ + if (pattern_len == 0) + { + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, + _("auto-load: Matched - empty pattern\n")); + return 1; + } + + for (;;) + { + /* Trim trailing slashes ("/"). PATTERN also has slashes trimmed the + same way so they will match. */ + while (filename_len && IS_DIR_SEPARATOR (filename[filename_len - 1])) + filename_len--; + filename[filename_len] = '\0'; + if (filename_len == 0) + { + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, + _("auto-load: Not matched - pattern \"%s\".\n"), + pattern); + return 0; + } + + if (gdb_filename_fnmatch (pattern, filename, FNM_FILE_NAME | FNM_NOESCAPE) + == 0) + { + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, _("auto-load: Matched - file " + "\"%s\" to pattern \"%s\".\n"), + filename, pattern); + return 1; + } + + /* Trim trailing FILENAME component. */ + while (filename_len > 0 && !IS_DIR_SEPARATOR (filename[filename_len - 1])) + filename_len--; + } +} + +/* Return 1 if FILENAME matches PATTERN or if FILENAME resides in + a subdirectory of a directory that matches PATTERN. Return 0 otherwise. + gdb_realpath normalization is never done here. */ + +static ATTRIBUTE_PURE int +filename_is_in_pattern (const char *filename, const char *pattern) +{ + char *filename_copy, *pattern_copy; + + filename_copy = alloca (strlen (filename) + 1); + strcpy (filename_copy, filename); + pattern_copy = alloca (strlen (pattern) + 1); + strcpy (pattern_copy, pattern); + + return filename_is_in_pattern_1 (filename_copy, pattern_copy); +} + +/* Return 1 if FILENAME belongs to one of directory components of + AUTO_LOAD_SAFE_PATH_VEC. Return 0 otherwise. + auto_load_safe_path_vec_update is never called. + *FILENAME_REALP may be updated by gdb_realpath of FILENAME - it has to be + freed by the caller. */ + +static int +filename_is_in_auto_load_safe_path_vec (const char *filename, + char **filename_realp) +{ + char *pattern; + int ix; + + for (ix = 0; VEC_iterate (char_ptr, auto_load_safe_path_vec, ix, pattern); + ++ix) + if (*filename_realp == NULL && filename_is_in_pattern (filename, pattern)) + break; + + if (pattern == NULL) + { + if (*filename_realp == NULL) + { + *filename_realp = gdb_realpath (filename); + if (debug_auto_load && strcmp (*filename_realp, filename) != 0) + fprintf_unfiltered (gdb_stdlog, + _("auto-load: Resolved " + "file \"%s\" as \"%s\".\n"), + filename, *filename_realp); + } + + if (strcmp (*filename_realp, filename) != 0) + for (ix = 0; + VEC_iterate (char_ptr, auto_load_safe_path_vec, ix, pattern); ++ix) + if (filename_is_in_pattern (*filename_realp, pattern)) + break; + } + + if (pattern != NULL) + { + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, _("auto-load: File \"%s\" matches " + "directory \"%s\".\n"), + filename, pattern); + return 1; + } + + return 0; +} + +/* Return 1 if FILENAME is located in one of the directories of + AUTO_LOAD_SAFE_PATH. Otherwise call warning and return 0. FILENAME does + not have to be an absolute path. + + Existence of FILENAME is not checked. Function will still give a warning + even if the caller would quietly skip non-existing file in unsafe + directory. */ + +int +file_is_auto_load_safe (const char *filename, const char *debug_fmt, ...) +{ + char *filename_real = NULL; + struct cleanup *back_to; + static int advice_printed = 0; + + if (debug_auto_load) + { + va_list debug_args; + + va_start (debug_args, debug_fmt); + vfprintf_unfiltered (gdb_stdlog, debug_fmt, debug_args); + va_end (debug_args); + } + + back_to = make_cleanup (free_current_contents, &filename_real); + + if (filename_is_in_auto_load_safe_path_vec (filename, &filename_real)) + { + do_cleanups (back_to); + return 1; + } + + auto_load_safe_path_vec_update (); + if (filename_is_in_auto_load_safe_path_vec (filename, &filename_real)) + { + do_cleanups (back_to); + return 1; + } + + warning (_("File \"%s\" auto-loading has been declined by your " + "`auto-load safe-path' set to \"%s\"."), + filename_real, auto_load_safe_path); + + if (!advice_printed) + { + const char *homedir = getenv ("HOME"); + char *homeinit; + + if (homedir == NULL) + homedir = "$HOME"; + homeinit = xstrprintf ("%s/%s", homedir, gdbinit); + make_cleanup (xfree, homeinit); + + printf_filtered (_("\ +To enable execution of this file add\n\ +\tadd-auto-load-safe-path %s\n\ +line to your configuration file \"%s\".\n\ +To completely disable this security protection add\n\ +\tset auto-load safe-path /\n\ +line to your configuration file \"%s\".\n\ +For more information about this security protection see the\n\ +\"Auto-loading safe path\" section in the GDB manual. E.g., run from the shell:\n\ +\tinfo \"(gdb)Auto-loading safe path\"\n"), + filename_real, homeinit, homeinit); + advice_printed = 1; + } + + do_cleanups (back_to); + return 0; +} + +/* Definition of script language for GDB canned sequences of commands. */ + +static const struct script_language script_language_gdb + = { GDB_AUTO_FILE_NAME, source_gdb_script_for_objfile }; + +static void +source_gdb_script_for_objfile (struct objfile *objfile, FILE *file, + const char *filename) +{ + int is_safe; + struct auto_load_pspace_info *pspace_info; + volatile struct gdb_exception e; + + is_safe = file_is_auto_load_safe (filename, _("auto-load: Loading canned " + "sequences of commands script " + "\"%s\" for objfile \"%s\".\n"), + filename, objfile->name); + + /* Add this script to the hash table too so "info auto-load gdb-scripts" + can print it. */ + pspace_info = get_auto_load_pspace_data_for_loading (current_program_space); + maybe_add_script (pspace_info, is_safe, filename, filename, + &script_language_gdb); + + if (!is_safe) + return; + + TRY_CATCH (e, RETURN_MASK_ALL) + { + script_from_file (file, filename); + } + exception_print (gdb_stderr, e); +} + +/* For scripts specified in .debug_gdb_scripts, multiple objfiles may load + the same script. There's no point in loading the script multiple times, + and there can be a lot of objfiles and scripts, so we keep track of scripts + loaded this way. */ + +struct auto_load_pspace_info +{ + /* For each program space we keep track of loaded scripts. */ + struct htab *loaded_scripts; + + /* Non-zero if we've issued the warning about an auto-load script not being + found. We only want to issue this warning once. */ + int script_not_found_warning_printed; +}; + +/* Objects of this type are stored in the loaded script hash table. */ + +struct loaded_script +{ + /* Name as provided by the objfile. */ + const char *name; + + /* Full path name or NULL if script wasn't found (or was otherwise + inaccessible). */ + const char *full_path; + + /* Non-zero if this script has been loaded. */ + int loaded; + + const struct script_language *language; +}; + +/* Per-program-space data key. */ +static const struct program_space_data *auto_load_pspace_data; + +static void +auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg) +{ + struct auto_load_pspace_info *info; + + info = program_space_data (pspace, auto_load_pspace_data); + if (info != NULL) + { + if (info->loaded_scripts) + htab_delete (info->loaded_scripts); + xfree (info); + } +} + +/* Get the current autoload data. If none is found yet, add it now. This + function always returns a valid object. */ + +static struct auto_load_pspace_info * +get_auto_load_pspace_data (struct program_space *pspace) +{ + struct auto_load_pspace_info *info; + + info = program_space_data (pspace, auto_load_pspace_data); + if (info == NULL) + { + info = XZALLOC (struct auto_load_pspace_info); + set_program_space_data (pspace, auto_load_pspace_data, info); + } + + return info; +} + +/* Hash function for the loaded script hash. */ + +static hashval_t +hash_loaded_script_entry (const void *data) +{ + const struct loaded_script *e = data; + + return htab_hash_string (e->name) ^ htab_hash_pointer (e->language); +} + +/* Equality function for the loaded script hash. */ + +static int +eq_loaded_script_entry (const void *a, const void *b) +{ + const struct loaded_script *ea = a; + const struct loaded_script *eb = b; + + return strcmp (ea->name, eb->name) == 0 && ea->language == eb->language; +} + +/* Initialize the table to track loaded scripts. + Each entry is hashed by the full path name. */ + +static void +init_loaded_scripts_info (struct auto_load_pspace_info *pspace_info) +{ + /* Choose 31 as the starting size of the hash table, somewhat arbitrarily. + Space for each entry is obtained with one malloc so we can free them + easily. */ + + pspace_info->loaded_scripts = htab_create (31, + hash_loaded_script_entry, + eq_loaded_script_entry, + xfree); + + pspace_info->script_not_found_warning_printed = FALSE; +} + +/* Wrapper on get_auto_load_pspace_data to also allocate the hash table + for loading scripts. */ + +struct auto_load_pspace_info * +get_auto_load_pspace_data_for_loading (struct program_space *pspace) +{ + struct auto_load_pspace_info *info; + + info = get_auto_load_pspace_data (pspace); + if (info->loaded_scripts == NULL) + init_loaded_scripts_info (info); + + return info; +} + +/* Add script NAME in LANGUAGE to hash table of PSPACE_INFO. LOADED 1 if the + script has been (is going to) be loaded, 0 otherwise (such as if it has not + been found). FULL_PATH is NULL if the script wasn't found. The result is + true if the script was already in the hash table. */ + +int +maybe_add_script (struct auto_load_pspace_info *pspace_info, int loaded, + const char *name, const char *full_path, + const struct script_language *language) +{ + struct htab *htab = pspace_info->loaded_scripts; + struct loaded_script **slot, entry; + int in_hash_table; + + entry.name = name; + entry.language = language; + slot = (struct loaded_script **) htab_find_slot (htab, &entry, INSERT); + in_hash_table = *slot != NULL; + + /* If this script is not in the hash table, add it. */ + + if (! in_hash_table) + { + char *p; + + /* Allocate all space in one chunk so it's easier to free. */ + *slot = xmalloc (sizeof (**slot) + + strlen (name) + 1 + + (full_path != NULL ? (strlen (full_path) + 1) : 0)); + p = ((char*) *slot) + sizeof (**slot); + strcpy (p, name); + (*slot)->name = p; + if (full_path != NULL) + { + p += strlen (p) + 1; + strcpy (p, full_path); + (*slot)->full_path = p; + } + else + (*slot)->full_path = NULL; + (*slot)->loaded = loaded; + (*slot)->language = language; + } + + return in_hash_table; +} + +/* Clear the table of loaded section scripts. */ + +static void +clear_section_scripts (void) +{ + struct program_space *pspace = current_program_space; + struct auto_load_pspace_info *info; + + info = program_space_data (pspace, auto_load_pspace_data); + if (info != NULL && info->loaded_scripts != NULL) + { + htab_delete (info->loaded_scripts); + info->loaded_scripts = NULL; + info->script_not_found_warning_printed = FALSE; + } +} + +/* Look for the auto-load script in LANGUAGE associated with OBJFILE where + OBJFILE's gdb_realpath is REALNAME and load it. Return 1 if we found any + matching script, return 0 otherwise. */ + +static int +auto_load_objfile_script_1 (struct objfile *objfile, const char *realname, + const struct script_language *language) +{ + char *filename, *debugfile; + int len, retval; + FILE *input; + struct cleanup *cleanups; + + len = strlen (realname); + filename = xmalloc (len + strlen (language->suffix) + 1); + memcpy (filename, realname, len); + strcpy (filename + len, language->suffix); + + cleanups = make_cleanup (xfree, filename); + + input = fopen (filename, "r"); + debugfile = filename; + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, _("auto-load: Attempted file \"%s\" %s.\n"), + debugfile, input ? _("exists") : _("does not exist")); + + if (!input) + { + VEC (char_ptr) *vec; + int ix; + char *dir; + + /* Also try the same file in a subdirectory of gdb's data + directory. */ + + vec = auto_load_expand_dir_vars (auto_load_dir); + make_cleanup_free_char_ptr_vec (vec); + + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, _("auto-load: Searching 'set auto-load " + "scripts-directory' path \"%s\".\n"), + auto_load_dir); + + for (ix = 0; VEC_iterate (char_ptr, vec, ix, dir); ++ix) + { + debugfile = xmalloc (strlen (dir) + strlen (filename) + 1); + strcpy (debugfile, dir); + + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, _("auto-load: Attempted file " + "\"%s\" %s.\n"), + debugfile, + input ? _("exists") : _("does not exist")); + if (input != NULL) + break; + } + } + + if (input) + { + make_cleanup_fclose (input); + + /* To preserve existing behaviour we don't check for whether the + script was already in the table, and always load it. + It's highly unlikely that we'd ever load it twice, + and these scripts are required to be idempotent under multiple + loads anyway. */ + language->source_script_for_objfile (objfile, input, debugfile); + + retval = 1; + } + else + retval = 0; + + do_cleanups (cleanups); + return retval; +} + +/* Look for the auto-load script in LANGUAGE associated with OBJFILE and load + it. */ + +void +auto_load_objfile_script (struct objfile *objfile, + const struct script_language *language) +{ + char *realname = gdb_realpath (objfile->name); + struct cleanup *cleanups = make_cleanup (xfree, realname); + + if (!auto_load_objfile_script_1 (objfile, realname, language)) + { + /* For Windows/DOS .exe executables, strip the .exe suffix, so that + FOO-gdb.gdb could be used for FOO.exe, and try again. */ + + size_t len = strlen (realname); + const size_t lexe = sizeof (".exe") - 1; + + if (len > lexe && strcasecmp (realname + len - lexe, ".exe") == 0) + { + len -= lexe; + realname[len] = '\0'; + if (debug_auto_load) + fprintf_unfiltered (gdb_stdlog, _("auto-load: Stripped .exe suffix, " + "retrying with \"%s\".\n"), + realname); + auto_load_objfile_script_1 (objfile, realname, language); + } + } + + do_cleanups (cleanups); +} + +/* Load any auto-loaded scripts for OBJFILE. */ + +void +load_auto_scripts_for_objfile (struct objfile *objfile) +{ + if (!global_auto_load) + return; + + if (auto_load_gdb_scripts) + auto_load_objfile_script (objfile, &script_language_gdb); + + gdbpy_load_auto_scripts_for_objfile (objfile); +} + +/* This is a new_objfile observer callback to auto-load scripts. + + Two flavors of auto-loaded scripts are supported. + 1) based on the path to the objfile + 2) from .debug_gdb_scripts section */ + +static void +auto_load_new_objfile (struct objfile *objfile) +{ + if (!objfile) + { + /* OBJFILE is NULL when loading a new "main" symbol-file. */ + clear_section_scripts (); + return; + } + + load_auto_scripts_for_objfile (objfile); +} + +/* Collect scripts to be printed in a vec. */ + +typedef struct loaded_script *loaded_script_ptr; +DEF_VEC_P (loaded_script_ptr); + +struct collect_matching_scripts_data +{ + VEC (loaded_script_ptr) **scripts_p; + + const struct script_language *language; +}; + +/* Traversal function for htab_traverse. + Collect the entry if it matches the regexp. */ + +static int +collect_matching_scripts (void **slot, void *info) +{ + struct loaded_script *script = *slot; + struct collect_matching_scripts_data *data = info; + + if (script->language == data->language && re_exec (script->name)) + VEC_safe_push (loaded_script_ptr, *data->scripts_p, script); + + return 1; +} + +/* Print SCRIPT. */ + +static void +print_script (struct loaded_script *script) +{ + struct ui_out *uiout = current_uiout; + struct cleanup *chain; + + chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); + + ui_out_field_string (uiout, "loaded", script->loaded ? "Yes" : "No"); + ui_out_field_string (uiout, "script", script->name); + ui_out_text (uiout, "\n"); + + /* If the name isn't the full path, print it too. */ + if (script->full_path != NULL + && strcmp (script->name, script->full_path) != 0) + { + ui_out_text (uiout, "\tfull name: "); + ui_out_field_string (uiout, "full_path", script->full_path); + ui_out_text (uiout, "\n"); + } + + do_cleanups (chain); +} + +/* Helper for info_auto_load_scripts to sort the scripts by name. */ + +static int +sort_scripts_by_name (const void *ap, const void *bp) +{ + const struct loaded_script *a = *(const struct loaded_script **) ap; + const struct loaded_script *b = *(const struct loaded_script **) bp; + + return FILENAME_CMP (a->name, b->name); +} + +/* Special internal GDB value of auto_load_info_scripts's PATTERN identify + the "info auto-load XXX" command has been executed through the general + "info auto-load" invocation. Extra newline will be printed if needed. */ +char auto_load_info_scripts_pattern_nl[] = ""; + +/* Implementation for "info auto-load gdb-scripts" + (and "info auto-load python-scripts"). List scripts in LANGUAGE matching + PATTERN. FROM_TTY is the usual GDB boolean for user interactivity. */ + +void +auto_load_info_scripts (char *pattern, int from_tty, + const struct script_language *language) +{ + struct ui_out *uiout = current_uiout; + struct auto_load_pspace_info *pspace_info; + struct cleanup *script_chain; + VEC (loaded_script_ptr) *scripts; + int nr_scripts; + + dont_repeat (); + + pspace_info = get_auto_load_pspace_data (current_program_space); + + if (pattern && *pattern) + { + char *re_err = re_comp (pattern); + + if (re_err) + error (_("Invalid regexp: %s"), re_err); + } + else + { + re_comp (""); + } + + /* We need to know the number of rows before we build the table. + Plus we want to sort the scripts by name. + So first traverse the hash table collecting the matching scripts. */ + + scripts = VEC_alloc (loaded_script_ptr, 10); + script_chain = make_cleanup (VEC_cleanup (loaded_script_ptr), &scripts); + + if (pspace_info != NULL && pspace_info->loaded_scripts != NULL) + { + struct collect_matching_scripts_data data = { &scripts, language }; + + /* Pass a pointer to scripts as VEC_safe_push can realloc space. */ + htab_traverse_noresize (pspace_info->loaded_scripts, + collect_matching_scripts, &data); + } + + nr_scripts = VEC_length (loaded_script_ptr, scripts); + + /* Table header shifted right by preceding "gdb-scripts: " would not match + its columns. */ + if (nr_scripts > 0 && pattern == auto_load_info_scripts_pattern_nl) + ui_out_text (uiout, "\n"); + + make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, + "AutoLoadedScriptsTable"); + + ui_out_table_header (uiout, 7, ui_left, "loaded", "Loaded"); + ui_out_table_header (uiout, 70, ui_left, "script", "Script"); + ui_out_table_body (uiout); + + if (nr_scripts > 0) + { + int i; + loaded_script_ptr script; + + qsort (VEC_address (loaded_script_ptr, scripts), + VEC_length (loaded_script_ptr, scripts), + sizeof (loaded_script_ptr), sort_scripts_by_name); + for (i = 0; VEC_iterate (loaded_script_ptr, scripts, i, script); ++i) + print_script (script); + } + + do_cleanups (script_chain); + + if (nr_scripts == 0) + { + if (pattern && *pattern) + ui_out_message (uiout, 0, "No auto-load scripts matching %s.\n", + pattern); + else + ui_out_message (uiout, 0, "No auto-load scripts.\n"); + } +} + +/* Wrapper for "info auto-load gdb-scripts". */ + +static void +info_auto_load_gdb_scripts (char *pattern, int from_tty) +{ + auto_load_info_scripts (pattern, from_tty, &script_language_gdb); +} + +/* Implement 'info auto-load local-gdbinit'. */ + +static void +info_auto_load_local_gdbinit (char *args, int from_tty) +{ + if (auto_load_local_gdbinit_pathname == NULL) + printf_filtered (_("Local .gdbinit file was not found.\n")); + else if (auto_load_local_gdbinit_loaded) + printf_filtered (_("Local .gdbinit file \"%s\" has been loaded.\n"), + auto_load_local_gdbinit_pathname); + else + printf_filtered (_("Local .gdbinit file \"%s\" has not been loaded.\n"), + auto_load_local_gdbinit_pathname); +} + +/* Return non-zero if SCRIPT_NOT_FOUND_WARNING_PRINTED of PSPACE_INFO was unset + before calling this function. Always set SCRIPT_NOT_FOUND_WARNING_PRINTED + of PSPACE_INFO. */ + +int +script_not_found_warning_print (struct auto_load_pspace_info *pspace_info) +{ + int retval = !pspace_info->script_not_found_warning_printed; + + pspace_info->script_not_found_warning_printed = 1; + + return retval; +} + +/* The only valid "set auto-load" argument is off|0|no|disable. */ + +static void +set_auto_load_cmd (char *args, int from_tty) +{ + struct cmd_list_element *list; + size_t length; + + /* See parse_binary_operation in use by the sub-commands. */ + + length = args ? strlen (args) : 0; + + while (length > 0 && (args[length - 1] == ' ' || args[length - 1] == '\t')) + length--; + + if (length == 0 || (strncmp (args, "off", length) != 0 + && strncmp (args, "0", length) != 0 + && strncmp (args, "no", length) != 0 + && strncmp (args, "disable", length) != 0)) + error (_("Valid is only global 'set auto-load no'; " + "otherwise check the auto-load sub-commands.")); + + for (list = *auto_load_set_cmdlist_get (); list != NULL; list = list->next) + if (list->var_type == var_boolean) + { + gdb_assert (list->type == set_cmd); + do_set_command (args, from_tty, list); + } +} + +/* Initialize "set auto-load " commands prefix and return it. */ + +struct cmd_list_element ** +auto_load_set_cmdlist_get (void) +{ + static struct cmd_list_element *retval; + + if (retval == NULL) + add_prefix_cmd ("auto-load", class_maintenance, set_auto_load_cmd, _("\ +Auto-loading specific settings.\n\ +Configure various auto-load-specific variables such as\n\ +automatic loading of Python scripts."), + &retval, "set auto-load ", + 1/*allow-unknown*/, &setlist); + + return &retval; +} + +/* Command "show auto-load" displays summary of all the current + "show auto-load " settings. */ + +static void +show_auto_load_cmd (char *args, int from_tty) +{ + cmd_show_list (*auto_load_show_cmdlist_get (), from_tty, ""); +} + +/* Initialize "show auto-load " commands prefix and return it. */ + +struct cmd_list_element ** +auto_load_show_cmdlist_get (void) +{ + static struct cmd_list_element *retval; + + if (retval == NULL) + add_prefix_cmd ("auto-load", class_maintenance, show_auto_load_cmd, _("\ +Show auto-loading specific settings.\n\ +Show configuration of various auto-load-specific variables such as\n\ +automatic loading of Python scripts."), + &retval, "show auto-load ", + 0/*allow-unknown*/, &showlist); + + return &retval; +} + +/* Command "info auto-load" displays whether the various auto-load files have + been loaded. This is reimplementation of cmd_show_list which inserts + newlines at proper places. */ + +static void +info_auto_load_cmd (char *args, int from_tty) +{ + struct cmd_list_element *list; + struct cleanup *infolist_chain; + struct ui_out *uiout = current_uiout; + + infolist_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "infolist"); + + for (list = *auto_load_info_cmdlist_get (); list != NULL; list = list->next) + { + struct cleanup *option_chain + = make_cleanup_ui_out_tuple_begin_end (uiout, "option"); + + gdb_assert (!list->prefixlist); + gdb_assert (list->type == not_set_cmd); + + ui_out_field_string (uiout, "name", list->name); + ui_out_text (uiout, ": "); + cmd_func (list, auto_load_info_scripts_pattern_nl, from_tty); + + /* Close the tuple. */ + do_cleanups (option_chain); + } + + /* Close the tuple. */ + do_cleanups (infolist_chain); +} + +/* Initialize "info auto-load " commands prefix and return it. */ + +struct cmd_list_element ** +auto_load_info_cmdlist_get (void) +{ + static struct cmd_list_element *retval; + + if (retval == NULL) + add_prefix_cmd ("auto-load", class_info, info_auto_load_cmd, _("\ +Print current status of auto-loaded files.\n\ +Print whether various files like Python scripts or .gdbinit files have been\n\ +found and/or loaded."), + &retval, "info auto-load ", + 0/*allow-unknown*/, &infolist); + + return &retval; +} + +void _initialize_auto_load (void); + +void +_initialize_auto_load (void) +{ + struct cmd_list_element *cmd; + char *scripts_directory_help; + + auto_load_pspace_data + = register_program_space_data_with_cleanup (NULL, + auto_load_pspace_data_cleanup); + + observer_attach_new_objfile (auto_load_new_objfile); + + add_setshow_boolean_cmd ("gdb-scripts", class_support, + &auto_load_gdb_scripts, _("\ +Enable or disable auto-loading of canned sequences of commands scripts."), _("\ +Show whether auto-loading of canned sequences of commands scripts is enabled."), + _("\ +If enabled, canned sequences of commands are loaded when the debugger reads\n\ +an executable or shared library.\n\ +This options has security implications for untrusted inferiors."), + NULL, show_auto_load_gdb_scripts, + auto_load_set_cmdlist_get (), + auto_load_show_cmdlist_get ()); + + add_cmd ("gdb-scripts", class_info, info_auto_load_gdb_scripts, + _("Print the list of automatically loaded sequences of commands.\n\ +Usage: info auto-load gdb-scripts [REGEXP]"), + auto_load_info_cmdlist_get ()); + + add_setshow_boolean_cmd ("local-gdbinit", class_support, + &auto_load_local_gdbinit, _("\ +Enable or disable auto-loading of .gdbinit script in current directory."), _("\ +Show whether auto-loading .gdbinit script in current directory is enabled."), + _("\ +If enabled, canned sequences of commands are loaded when debugger starts\n\ +from .gdbinit file in current directory. Such files are deprecated,\n\ +use a script associated with inferior executable file instead.\n\ +This options has security implications for untrusted inferiors."), + NULL, show_auto_load_local_gdbinit, + auto_load_set_cmdlist_get (), + auto_load_show_cmdlist_get ()); + + add_cmd ("local-gdbinit", class_info, info_auto_load_local_gdbinit, + _("Print whether current directory .gdbinit file has been loaded.\n\ +Usage: info auto-load local-gdbinit"), + auto_load_info_cmdlist_get ()); + + auto_load_dir = xstrdup (AUTO_LOAD_DIR); + scripts_directory_help = xstrprintf ( +#ifdef HAVE_PYTHON + _("\ +Automatically loaded Python scripts (named OBJFILE%s) and GDB scripts\n\ +(named OBJFILE%s) are located in one of the directories listed by this\n\ +option.\n\ +%s"), + GDBPY_AUTO_FILE_NAME, +#else + _("\ +Automatically loaded GDB scripts (named OBJFILE%s) are located in one\n\ +of the directories listed by this option.\n\ +%s"), +#endif + GDB_AUTO_FILE_NAME, + _("\ +This option is ignored for the kinds of scripts \ +having 'set auto-load ... off'.\n\ +Directories listed here need to be present also \ +in the 'set auto-load safe-path'\n\ +option.")); + add_setshow_optional_filename_cmd ("scripts-directory", class_support, + &auto_load_dir, _("\ +Set the list of directories from which to load auto-loaded scripts."), _("\ +Show the list of directories from which to load auto-loaded scripts."), + scripts_directory_help, + set_auto_load_dir, show_auto_load_dir, + auto_load_set_cmdlist_get (), + auto_load_show_cmdlist_get ()); + xfree (scripts_directory_help); + + auto_load_safe_path = xstrdup (AUTO_LOAD_SAFE_PATH); + auto_load_safe_path_vec_update (); + add_setshow_optional_filename_cmd ("safe-path", class_support, + &auto_load_safe_path, _("\ +Set the list of files and directories that are safe for auto-loading."), _("\ +Show the list of files and directories that are safe for auto-loading."), _("\ +Various files loaded automatically for the 'set auto-load ...' options must\n\ +be located in one of the directories listed by this option. Warning will be\n\ +printed and file will not be used otherwise.\n\ +You can mix both directory and filename entries.\n\ +Setting this parameter to an empty list resets it to its default value.\n\ +Setting this parameter to '/' (without the quotes) allows any file\n\ +for the 'set auto-load ...' options. Each path entry can be also shell\n\ +wildcard pattern; '*' does not match directory separator.\n\ +This option is ignored for the kinds of files having 'set auto-load ... off'.\n\ +This options has security implications for untrusted inferiors."), + set_auto_load_safe_path, + show_auto_load_safe_path, + auto_load_set_cmdlist_get (), + auto_load_show_cmdlist_get ()); + observer_attach_gdb_datadir_changed (auto_load_gdb_datadir_changed); + + cmd = add_cmd ("add-auto-load-safe-path", class_support, + add_auto_load_safe_path, + _("Add entries to the list of directories from which it is safe " + "to auto-load files.\n\ +See the commands 'set auto-load safe-path' and 'show auto-load safe-path' to\n\ +access the current full list setting."), + &cmdlist); + set_cmd_completer (cmd, filename_completer); + + add_setshow_boolean_cmd ("auto-load", class_maintenance, + &debug_auto_load, _("\ +Set auto-load verifications debugging."), _("\ +Show auto-load verifications debugging."), _("\ +When non-zero, debugging output for files of 'set auto-load ...'\n\ +is displayed."), + NULL, show_debug_auto_load, + &setdebuglist, &showdebuglist); +} diff --git a/contrib/gdb-7/gdb/auto-load.h b/contrib/gdb-7/gdb/auto-load.h new file mode 100644 index 0000000000..6a666229dd --- /dev/null +++ b/contrib/gdb-7/gdb/auto-load.h @@ -0,0 +1,61 @@ +/* GDB routines for supporting auto-loaded scripts. + + Copyright (C) 2012-2013 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 AUTO_LOAD_H +#define AUTO_LOAD_H 1 + +struct program_space; + +struct script_language +{ + const char *suffix; + + void (*source_script_for_objfile) (struct objfile *objfile, FILE *file, + const char *filename); +}; + +extern int global_auto_load; + +extern int auto_load_local_gdbinit; +extern char *auto_load_local_gdbinit_pathname; +extern int auto_load_local_gdbinit_loaded; + +extern struct auto_load_pspace_info * + get_auto_load_pspace_data_for_loading (struct program_space *pspace); +extern int maybe_add_script (struct auto_load_pspace_info *pspace_info, + int loaded, const char *name, + const char *full_path, + const struct script_language *language); +extern void auto_load_objfile_script (struct objfile *objfile, + const struct script_language *language); +extern void load_auto_scripts_for_objfile (struct objfile *objfile); +extern int + script_not_found_warning_print (struct auto_load_pspace_info *pspace_info); +extern char auto_load_info_scripts_pattern_nl[]; +extern void auto_load_info_scripts (char *pattern, int from_tty, + const struct script_language *language); + +extern struct cmd_list_element **auto_load_set_cmdlist_get (void); +extern struct cmd_list_element **auto_load_show_cmdlist_get (void); +extern struct cmd_list_element **auto_load_info_cmdlist_get (void); + +extern int file_is_auto_load_safe (const char *filename, + const char *debug_fmt, ...); + +#endif /* AUTO_LOAD_H */ diff --git a/contrib/gdb-7/gdb/auxv.c b/contrib/gdb-7/gdb/auxv.c index 23d1480689..3a63a65d6c 100644 --- a/contrib/gdb-7/gdb/auxv.c +++ b/contrib/gdb-7/gdb/auxv.c @@ -1,6 +1,6 @@ /* Auxiliary vector support for GDB, the GNU debugger. - Copyright (C) 2004-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -76,7 +76,7 @@ ld_so_xfer_auxv (gdb_byte *readbuf, { struct minimal_symbol *msym; CORE_ADDR data_address, pointer_address; - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; size_t ptr_size = TYPE_LENGTH (ptr_type); size_t auxv_pair_size = 2 * ptr_size; gdb_byte *ptr_buf = alloca (ptr_size); @@ -240,9 +240,9 @@ static int default_auxv_parse (struct target_ops *ops, gdb_byte **readptr, gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) { - const int sizeof_auxv_field = gdbarch_ptr_bit (target_gdbarch) + const int sizeof_auxv_field = gdbarch_ptr_bit (target_gdbarch ()) / TARGET_CHAR_BIT; - const enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + const enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); gdb_byte *ptr = *readptr; if (endptr == ptr) @@ -445,6 +445,10 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), dec); TAG (AT_SYSINFO, _("Special system info/entry points"), hex); TAG (AT_SYSINFO_EHDR, _("System-supplied DSO's ELF header"), hex); + TAG (AT_L1I_CACHESHAPE, _("L1 Instruction cache information"), hex); + TAG (AT_L1D_CACHESHAPE, _("L1 Data cache information"), hex); + TAG (AT_L2_CACHESHAPE, _("L2 cache information"), hex); + TAG (AT_L3_CACHESHAPE, _("L3 cache information"), hex); TAG (AT_SUN_UID, _("Effective user ID"), dec); TAG (AT_SUN_RUID, _("Real user ID"), dec); TAG (AT_SUN_GID, _("Effective group ID"), dec); @@ -475,7 +479,7 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) fprintf_filtered (file, "%s\n", plongest (val)); break; case hex: - fprintf_filtered (file, "%s\n", paddress (target_gdbarch, val)); + fprintf_filtered (file, "%s\n", paddress (target_gdbarch (), val)); break; case str: { @@ -483,8 +487,8 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) get_user_print_options (&opts); if (opts.addressprint) - fprintf_filtered (file, "%s", paddress (target_gdbarch, val)); - val_print_string (builtin_type (target_gdbarch)->builtin_char, + fprintf_filtered (file, "%s ", paddress (target_gdbarch (), val)); + val_print_string (builtin_type (target_gdbarch ())->builtin_char, NULL, val, -1, file, &opts); fprintf_filtered (file, "\n"); } @@ -526,7 +530,7 @@ This is information provided by the operating system at program startup.")); /* Set an auxv cache per-inferior. */ auxv_inferior_data - = register_inferior_data_with_cleanup (auxv_inferior_data_cleanup); + = register_inferior_data_with_cleanup (NULL, auxv_inferior_data_cleanup); /* Observers used to invalidate the auxv cache when needed. */ observer_attach_inferior_exit (invalidate_auxv_cache_inf); diff --git a/contrib/gdb-7/gdb/auxv.h b/contrib/gdb-7/gdb/auxv.h index cba5fe067d..0244cd82f8 100644 --- a/contrib/gdb-7/gdb/auxv.h +++ b/contrib/gdb-7/gdb/auxv.h @@ -1,6 +1,6 @@ /* Auxiliary vector support for GDB, the GNU debugger. - Copyright (C) 2004-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/ax-gdb.c b/contrib/gdb-7/gdb/ax-gdb.c index 31e91b9315..74824d373a 100644 --- a/contrib/gdb-7/gdb/ax-gdb.c +++ b/contrib/gdb-7/gdb/ax-gdb.c @@ -1,7 +1,6 @@ /* GDB-specific functions for operating on agent expressions. - Copyright (C) 1998-2001, 2003, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 1998-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -41,10 +40,14 @@ #include "tracepoint.h" #include "cp-support.h" #include "arch-utils.h" +#include "cli/cli-utils.h" +#include "linespec.h" #include "valprint.h" #include "c-lang.h" +#include "format.h" + /* To make sense of this file, you should read doc/agentexpr.texi. Then look at the types and enums in ax-gdb.h. For the code itself, look at gen_expr, towards the bottom; that's the main function that @@ -95,8 +98,6 @@ static void gen_int_literal (struct agent_expr *ax, struct axs_value *value, LONGEST k, struct type *type); - -static void require_rvalue (struct agent_expr *ax, struct axs_value *value); static void gen_usual_unary (struct expression *exp, struct agent_expr *ax, struct axs_value *value); static int type_wider_than (struct type *type1, struct type *type2); @@ -157,8 +158,6 @@ static void gen_repeat (struct expression *exp, union exp_element **pc, static void gen_sizeof (struct expression *exp, union exp_element **pc, struct agent_expr *ax, struct axs_value *value, struct type *size_type); -static void gen_expr (struct expression *exp, union exp_element **pc, - struct agent_expr *ax, struct axs_value *value); static void gen_expr_binop_rest (struct expression *exp, enum exp_opcode op, union exp_element **pc, struct agent_expr *ax, @@ -367,9 +366,9 @@ gen_trace_static_fields (struct gdbarch *gdbarch, { case axs_lvalue_memory: { - int length = TYPE_LENGTH (check_typedef (value.type)); - - ax_const_l (ax, length); + /* Initialize the TYPE_LENGTH if it is a typedef. */ + check_typedef (value.type); + ax_const_l (ax, TYPE_LENGTH (value.type)); ax_simple (ax, aop_trace); } break; @@ -425,17 +424,18 @@ gen_traced_pop (struct gdbarch *gdbarch, case axs_lvalue_memory: { - int length = TYPE_LENGTH (check_typedef (value->type)); - if (string_trace) ax_simple (ax, aop_dup); + /* Initialize the TYPE_LENGTH if it is a typedef. */ + check_typedef (value->type); + /* There's no point in trying to use a trace_quick bytecode here, since "trace_quick SIZE pop" is three bytes, whereas "const8 SIZE trace" is also three bytes, does the same thing, and the simplest code which generates that will also work correctly for objects with large sizes. */ - ax_const_l (ax, length); + ax_const_l (ax, TYPE_LENGTH (value->type)); ax_simple (ax, aop_trace); if (string_trace) @@ -515,6 +515,9 @@ gen_fetch (struct agent_expr *ax, struct type *type) ax_trace_quick (ax, TYPE_LENGTH (type)); } + if (TYPE_CODE (type) == TYPE_CODE_RANGE) + type = TYPE_TARGET_TYPE (type); + switch (TYPE_CODE (type)) { case TYPE_CODE_PTR: @@ -553,12 +556,11 @@ gen_fetch (struct agent_expr *ax, struct type *type) break; default: - /* Either our caller shouldn't have asked us to dereference that - pointer (other code's fault), or we're not implementing - something we should be (this code's fault). In any case, - it's a bug the user shouldn't see. */ - internal_error (__FILE__, __LINE__, - _("gen_fetch: bad type code")); + /* Our caller requested us to dereference a pointer from an unsupported + type. Error out and give callers a chance to handle the failure + gracefully. */ + error (_("gen_fetch: Unsupported type code `%s'."), + TYPE_NAME (type)); } } @@ -789,7 +791,7 @@ gen_int_literal (struct agent_expr *ax, struct axs_value *value, LONGEST k, /* Take what's on the top of the stack (as described by VALUE), and try to make an rvalue out of it. Signal an error if we can't do that. */ -static void +void require_rvalue (struct agent_expr *ax, struct axs_value *value) { /* Only deal with scalars, structs and such may be too large @@ -878,12 +880,6 @@ gen_usual_unary (struct expression *exp, struct agent_expr *ax, case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: return; - - /* If the value is an enum or a bool, call it an integer. */ - case TYPE_CODE_ENUM: - case TYPE_CODE_BOOL: - value->type = builtin_type (exp->gdbarch)->builtin_int; - break; } /* If the value is an lvalue, dereference it. */ @@ -1477,7 +1473,7 @@ gen_struct_ref_recursive (struct expression *exp, struct agent_expr *ax, for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--) { - char *this_name = TYPE_FIELD_NAME (type, i); + const char *this_name = TYPE_FIELD_NAME (type, i); if (this_name) { @@ -1625,7 +1621,7 @@ gen_struct_elt_for_reference (struct expression *exp, for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--) { - char *t_field_name = TYPE_FIELD_NAME (t, i); + const char *t_field_name = TYPE_FIELD_NAME (t, i); if (t_field_name && strcmp (t_field_name, fieldname) == 0) { @@ -1807,7 +1803,7 @@ gen_sizeof (struct expression *exp, union exp_element **pc, /* XXX: i18n */ /* A gen_expr function written by a Gen-X'er guy. Append code for the subexpression of EXPR starting at *POS_P to AX. */ -static void +void gen_expr (struct expression *exp, union exp_element **pc, struct agent_expr *ax, struct axs_value *value) { @@ -2042,7 +2038,8 @@ gen_expr (struct expression *exp, union exp_element **pc, case OP_INTERNALVAR: { - const char *name = internalvar_name ((*pc)[1].internalvar); + struct internalvar *var = (*pc)[1].internalvar; + const char *name = internalvar_name (var); struct trace_state_variable *tsv; (*pc) += 3; @@ -2056,7 +2053,7 @@ gen_expr (struct expression *exp, union exp_element **pc, value->kind = axs_rvalue; value->type = builtin_type (exp->gdbarch)->builtin_long_long; } - else + else if (! compile_internalvar_to_ax (var, ax, value)) error (_("$%s is not a trace state variable; GDB agent " "expressions cannot use convenience variables."), name); } @@ -2079,6 +2076,23 @@ gen_expr (struct expression *exp, union exp_element **pc, } break; + case UNOP_CAST_TYPE: + { + int offset; + struct value *val; + struct type *type; + + ++*pc; + offset = *pc - exp->elts; + val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS); + type = value_type (val); + *pc = &exp->elts[offset]; + + gen_expr (exp, pc, ax, value); + gen_cast (ax, value, type); + } + break; + case UNOP_MEMVAL: { struct type *type = check_typedef ((*pc)[1].type); @@ -2097,6 +2111,31 @@ gen_expr (struct expression *exp, union exp_element **pc, } break; + case UNOP_MEMVAL_TYPE: + { + int offset; + struct value *val; + struct type *type; + + ++*pc; + offset = *pc - exp->elts; + val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS); + type = value_type (val); + *pc = &exp->elts[offset]; + + gen_expr (exp, pc, ax, value); + + /* If we have an axs_rvalue or an axs_lvalue_memory, then we + already have the right value on the stack. For + axs_lvalue_register, we must convert. */ + if (value->kind == axs_lvalue_register) + require_rvalue (ax, value); + + value->type = type; + value->kind = axs_lvalue_memory; + } + break; + case UNOP_PLUS: (*pc)++; /* + FOO is equivalent to 0 + FOO, which can be optimized. */ @@ -2178,7 +2217,6 @@ gen_expr (struct expression *exp, union exp_element **pc, case OP_THIS: { - char *this_name; struct symbol *sym, *func; struct block *b; const struct language_defn *lang; @@ -2217,11 +2255,13 @@ gen_expr (struct expression *exp, union exp_element **pc, break; case OP_TYPE: + case OP_TYPEOF: + case OP_DECLTYPE: error (_("Attempt to use a type name as an expression.")); default: error (_("Unsupported operator %s (%d) in expression."), - op_string (op), op); + op_name (exp, op), op); } } @@ -2511,41 +2551,86 @@ gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch) return ax; } +/* Given a collection of printf-style arguments, generate code to + evaluate the arguments and pass everything to a special + bytecode. */ + +struct agent_expr * +gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch, + CORE_ADDR function, LONGEST channel, + const char *format, int fmtlen, + struct format_piece *frags, + int nargs, struct expression **exprs) +{ + struct cleanup *old_chain = 0; + struct agent_expr *ax = new_agent_expr (gdbarch, scope); + union exp_element *pc; + struct axs_value value; + int tem; + + old_chain = make_cleanup_free_agent_expr (ax); + + /* Evaluate and push the args on the stack in reverse order, + for simplicity of collecting them on the target side. */ + for (tem = nargs - 1; tem >= 0; --tem) + { + pc = exprs[tem]->elts; + /* We're computing values, not doing side effects. */ + trace_kludge = 0; + value.optimized_out = 0; + gen_expr (exprs[tem], &pc, ax, &value); + require_rvalue (ax, &value); + } + + /* Push function and channel. */ + ax_const_l (ax, channel); + ax_const_l (ax, function); + + /* Issue the printf bytecode proper. */ + ax_simple (ax, aop_printf); + ax_simple (ax, nargs); + ax_string (ax, format, fmtlen); + + /* And terminate. */ + ax_simple (ax, aop_end); + + /* We have successfully built the agent expr, so cancel the cleanup + request. If we add more cleanups that we always want done, this + will have to get more complicated. */ + discard_cleanups (old_chain); + + return ax; +} + static void -agent_command (char *exp, int from_tty) +agent_eval_command_one (char *exp, int eval, CORE_ADDR pc) { struct cleanup *old_chain = 0; struct expression *expr; struct agent_expr *agent; - struct frame_info *fi = get_current_frame (); /* need current scope */ + const char *arg; - /* We don't deal with overlay debugging at the moment. We need to - think more carefully about this. If you copy this code into - another command, change the error message; the user shouldn't - have to know anything about agent expressions. */ - if (overlay_debugging) - error (_("GDB can't do agent expression translation with overlays.")); - - if (exp == 0) - error_no_arg (_("expression to translate")); - - trace_string_kludge = 0; - if (*exp == '/') - exp = decode_agent_options (exp); + if (!eval) + { + trace_string_kludge = 0; + if (*exp == '/') + exp = decode_agent_options (exp); + } - /* Recognize the return address collection directive specially. Note - that it is not really an expression of any sort. */ - if (strcmp (exp, "$_ret") == 0) + arg = exp; + if (!eval && strcmp (arg, "$_ret") == 0) { - agent = gen_trace_for_return_address (get_frame_pc (fi), - get_current_arch ()); + agent = gen_trace_for_return_address (pc, get_current_arch ()); old_chain = make_cleanup_free_agent_expr (agent); } else { - expr = parse_expression (exp); + expr = parse_exp_1 (&arg, pc, block_for_pc (pc), 0); old_chain = make_cleanup (free_current_contents, &expr); - agent = gen_trace_for_expr (get_frame_pc (fi), expr); + if (eval) + agent = gen_eval_for_expr (pc, expr); + else + agent = gen_trace_for_expr (pc, expr); make_cleanup_free_agent_expr (agent); } @@ -2559,17 +2644,84 @@ agent_command (char *exp, int from_tty) dont_repeat (); } +static void +agent_command_1 (char *exp, int eval) +{ + /* We don't deal with overlay debugging at the moment. We need to + think more carefully about this. If you copy this code into + another command, change the error message; the user shouldn't + have to know anything about agent expressions. */ + if (overlay_debugging) + error (_("GDB can't do agent expression translation with overlays.")); + + if (exp == 0) + error_no_arg (_("expression to translate")); + + if (check_for_argument (&exp, "-at", sizeof ("-at") - 1)) + { + struct linespec_result canonical; + int ix; + struct linespec_sals *iter; + struct cleanup *old_chain; + + exp = skip_spaces (exp); + init_linespec_result (&canonical); + decode_line_full (&exp, DECODE_LINE_FUNFIRSTLINE, + (struct symtab *) NULL, 0, &canonical, + NULL, NULL); + old_chain = make_cleanup_destroy_linespec_result (&canonical); + exp = skip_spaces (exp); + if (exp[0] == ',') + { + exp++; + exp = skip_spaces (exp); + } + for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix) + { + int i; + + for (i = 0; i < iter->sals.nelts; i++) + agent_eval_command_one (exp, eval, iter->sals.sals[i].pc); + } + do_cleanups (old_chain); + } + else + agent_eval_command_one (exp, eval, get_frame_pc (get_current_frame ())); + + dont_repeat (); +} + +static void +agent_command (char *exp, int from_tty) +{ + agent_command_1 (exp, 0); +} + /* Parse the given expression, compile it into an agent expression that does direct evaluation, and display the resulting expression. */ static void agent_eval_command (char *exp, int from_tty) +{ + agent_command_1 (exp, 1); +} + +/* Parse the given expression, compile it into an agent expression + that does a printf, and display the resulting expression. */ + +static void +maint_agent_printf_command (char *exp, int from_tty) { struct cleanup *old_chain = 0; struct expression *expr; + struct expression *argvec[100]; struct agent_expr *agent; struct frame_info *fi = get_current_frame (); /* need current scope */ + const char *cmdrest; + const char *format_start, *format_end; + struct format_piece *fpieces; + int nargs; /* We don't deal with overlay debugging at the moment. We need to think more carefully about this. If you copy this code into @@ -2581,9 +2733,52 @@ agent_eval_command (char *exp, int from_tty) if (exp == 0) error_no_arg (_("expression to translate")); - expr = parse_expression (exp); - old_chain = make_cleanup (free_current_contents, &expr); - agent = gen_eval_for_expr (get_frame_pc (fi), expr); + cmdrest = exp; + + cmdrest = skip_spaces_const (cmdrest); + + if (*cmdrest++ != '"') + error (_("Must start with a format string.")); + + format_start = cmdrest; + + fpieces = parse_format_string (&cmdrest); + + old_chain = make_cleanup (free_format_pieces_cleanup, &fpieces); + + format_end = cmdrest; + + if (*cmdrest++ != '"') + error (_("Bad format string, non-terminated '\"'.")); + + cmdrest = skip_spaces_const (cmdrest); + + if (*cmdrest != ',' && *cmdrest != 0) + error (_("Invalid argument syntax")); + + if (*cmdrest == ',') + cmdrest++; + cmdrest = skip_spaces_const (cmdrest); + + nargs = 0; + while (*cmdrest != '\0') + { + const char *cmd1; + + cmd1 = cmdrest; + expr = parse_exp_1 (&cmd1, 0, (struct block *) 0, 1); + argvec[nargs] = expr; + ++nargs; + cmdrest = cmd1; + if (*cmdrest == ',') + ++cmdrest; + /* else complain? */ + } + + + agent = gen_printf (get_frame_pc (fi), get_current_arch (), 0, 0, + format_start, format_end - format_start, + fpieces, nargs, argvec); make_cleanup_free_agent_expr (agent); ax_reqs (agent); ax_print (gdb_stdout, agent); @@ -2603,12 +2798,23 @@ void _initialize_ax_gdb (void) { add_cmd ("agent", class_maintenance, agent_command, - _("Translate an expression into " - "remote agent bytecode for tracing."), + _("\ +Translate an expression into remote agent bytecode for tracing.\n\ +Usage: maint agent [-at location,] EXPRESSION\n\ +If -at is given, generate remote agent bytecode for this location.\n\ +If not, generate remote agent bytecode for current frame pc address."), &maintenancelist); add_cmd ("agent-eval", class_maintenance, agent_eval_command, + _("\ +Translate an expression into remote agent bytecode for evaluation.\n\ +Usage: maint agent-eval [-at location,] EXPRESSION\n\ +If -at is given, generate remote agent bytecode for this location.\n\ +If not, generate remote agent bytecode for current frame pc address."), + &maintenancelist); + + add_cmd ("agent-printf", class_maintenance, maint_agent_printf_command, _("Translate an expression into remote " - "agent bytecode for evaluation."), + "agent bytecode for evaluation and display the bytecodes."), &maintenancelist); } diff --git a/contrib/gdb-7/gdb/ax-gdb.h b/contrib/gdb-7/gdb/ax-gdb.h index 48c35a4a67..04772b77ff 100644 --- a/contrib/gdb-7/gdb/ax-gdb.h +++ b/contrib/gdb-7/gdb/ax-gdb.h @@ -1,5 +1,5 @@ /* GDB-specific functions for operating on agent expressions - Copyright (C) 1998-2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1998-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -110,6 +110,17 @@ extern struct agent_expr *gen_trace_for_return_address (CORE_ADDR, extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *); +extern void gen_expr (struct expression *exp, union exp_element **pc, + struct agent_expr *ax, struct axs_value *value); + +extern void require_rvalue (struct agent_expr *ax, struct axs_value *value); + +struct format_piece; +extern struct agent_expr *gen_printf (CORE_ADDR, struct gdbarch *, + CORE_ADDR, LONGEST, const char *, int, + struct format_piece *, + int, struct expression **); + extern int trace_kludge; extern int trace_string_kludge; diff --git a/contrib/gdb-7/gdb/ax-general.c b/contrib/gdb-7/gdb/ax-general.c index 4f1ea207af..8bd4df6acf 100644 --- a/contrib/gdb-7/gdb/ax-general.c +++ b/contrib/gdb-7/gdb/ax-general.c @@ -1,5 +1,5 @@ /* Functions for manipulating expressions designed to be executed on the agent - Copyright (C) 1998-2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1998-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -330,6 +330,30 @@ ax_tsv (struct agent_expr *x, enum agent_op op, int num) x->buf[x->len + 2] = (num) & 0xff; x->len += 3; } + +/* Append a string to the expression. Note that the string is going + into the bytecodes directly, not on the stack. As a precaution, + include both length as prefix, and terminate with a NUL. (The NUL + is counted in the length.) */ + +void +ax_string (struct agent_expr *x, const char *str, int slen) +{ + int i; + + /* Make sure the string length is reasonable. */ + if (slen < 0 || slen > 0xffff) + internal_error (__FILE__, __LINE__, + _("ax-general.c (ax_string): string " + "length is %d, out of allowed range"), slen); + + grow_expr (x, 2 + slen + 1); + x->buf[x->len++] = ((slen + 1) >> 8) & 0xff; + x->buf[x->len++] = (slen + 1) & 0xff; + for (i = 0; i < slen; ++i) + x->buf[x->len++] = str[i]; + x->buf[x->len++] = '\0'; +} @@ -351,7 +375,6 @@ void ax_print (struct ui_file *f, struct agent_expr *x) { int i; - int is_float = 0; fprintf_filtered (f, _("Scope: %s\n"), paddress (x->gdbarch, x->scope)); fprintf_filtered (f, _("Reg mask:")); @@ -391,10 +414,21 @@ ax_print (struct ui_file *f, struct agent_expr *x) print_longest (f, 'd', 0, read_const (x, i + 1, aop_map[op].op_size)); } + /* Handle the complicated printf arguments specially. */ + else if (op == aop_printf) + { + int slen, nargs; + + i++; + nargs = x->buf[i++]; + slen = x->buf[i++]; + slen = slen * 256 + x->buf[i++]; + fprintf_filtered (f, _(" \"%s\", %d args"), + &(x->buf[i]), nargs); + i += slen - 1; + } fprintf_filtered (f, "\n"); i += 1 + aop_map[op].op_size; - - is_float = (op == aop_float); } } diff --git a/contrib/gdb-7/gdb/ax.h b/contrib/gdb-7/gdb/ax.h index a25a3d158a..32887efeeb 100644 --- a/contrib/gdb-7/gdb/ax.h +++ b/contrib/gdb-7/gdb/ax.h @@ -1,5 +1,5 @@ /* Definitions for expressions designed to be executed on the agent - Copyright (C) 1998-2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1998-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -20,6 +20,7 @@ #define AGENTEXPR_H #include "doublest.h" /* For DOUBLEST. */ +#include "vec.h" /* It's sometimes useful to be able to debug programs that you can't really stop for more than a fraction of a second. To this end, the @@ -144,6 +145,12 @@ struct agent_expr unsigned char *reg_mask; }; +/* Pointer to an agent_expr structure. */ +typedef struct agent_expr *agent_expr_p; + +/* Vector of pointers to agent expressions. */ +DEF_VEC_P (agent_expr_p); + /* The actual values of the various bytecode operations. */ enum agent_op @@ -212,6 +219,9 @@ extern void ax_reg_mask (struct agent_expr *ax, int reg); /* Assemble code to operate on a trace state variable. */ extern void ax_tsv (struct agent_expr *expr, enum agent_op op, int num); + +/* Append a string to the bytecode stream. */ +extern void ax_string (struct agent_expr *x, const char *str, int slen); /* Functions for printing out expressions, and otherwise debugging diff --git a/contrib/gdb-7/gdb/bcache.c b/contrib/gdb-7/gdb/bcache.c index 2a180af605..712142dac7 100644 --- a/contrib/gdb-7/gdb/bcache.c +++ b/contrib/gdb-7/gdb/bcache.c @@ -2,8 +2,7 @@ Written by Fred Fish Rewritten by Jim Blandy - Copyright (C) 1999-2000, 2002-2003, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/bcache.h b/contrib/gdb-7/gdb/bcache.h index a52f932f21..fb37ec9e43 100644 --- a/contrib/gdb-7/gdb/bcache.h +++ b/contrib/gdb-7/gdb/bcache.h @@ -2,8 +2,7 @@ Written by Fred Fish Rewritten by Jim Blandy - Copyright (C) 1999-2000, 2002-2003, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/bfd-target.c b/contrib/gdb-7/gdb/bfd-target.c index 6728800461..ca32ffe9e9 100644 --- a/contrib/gdb-7/gdb/bfd-target.c +++ b/contrib/gdb-7/gdb/bfd-target.c @@ -1,6 +1,6 @@ /* Very simple "bfd" target, for GDB, the GNU debugger. - Copyright (C) 2003, 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -21,6 +21,7 @@ #include "target.h" #include "bfd-target.h" #include "exec.h" +#include "gdb_bfd.h" /* The object that is stored in the target_ops->to_data field has this type. */ @@ -70,7 +71,7 @@ target_bfd_xclose (struct target_ops *t, int quitting) { struct target_bfd_data *data = t->to_data; - bfd_close (data->bfd); + gdb_bfd_unref (data->bfd); xfree (data->table.sections); xfree (data); xfree (t); @@ -84,6 +85,7 @@ target_bfd_reopen (struct bfd *abfd) data = XZALLOC (struct target_bfd_data); data->bfd = abfd; + gdb_bfd_ref (abfd); build_section_table (abfd, &data->table.sections, &data->table.sections_end); t = XZALLOC (struct target_ops); diff --git a/contrib/gdb-7/gdb/bfd-target.h b/contrib/gdb-7/gdb/bfd-target.h index 71001c5f34..1c7f1943d2 100644 --- a/contrib/gdb-7/gdb/bfd-target.h +++ b/contrib/gdb-7/gdb/bfd-target.h @@ -1,6 +1,6 @@ /* Very simple "bfd" target, for GDB, the GNU debugger. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -23,9 +23,9 @@ struct bfd; struct target_ops; -/* Given an existing BFD, re-open it as a "struct target_ops". On - close, it will also close the corresponding BFD (which is like - freopen and fdopen). */ +/* Given an existing BFD, re-open it as a "struct target_ops". This + acquires a new reference to the BFD. This reference will be + released when the target is closed. */ struct target_ops *target_bfd_reopen (struct bfd *bfd); #endif diff --git a/contrib/gdb-7/gdb/block.c b/contrib/gdb-7/gdb/block.c index 57ab4c2024..2638de8f9a 100644 --- a/contrib/gdb-7/gdb/block.c +++ b/contrib/gdb-7/gdb/block.c @@ -1,6 +1,6 @@ /* Block-related functions for the GNU debugger, GDB. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -103,50 +103,28 @@ 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 - don't pass this information back to the caller. */ +/* A helper function that checks whether PC is in the blockvector BL. + It returns the containing block if there is one, or else NULL. */ -struct blockvector * -blockvector_for_pc_sect (CORE_ADDR pc, struct obj_section *section, - struct block **pblock, struct symtab *symtab) +static struct block * +find_block_in_blockvector (struct blockvector *bl, CORE_ADDR pc) { struct block *b; int bot, top, half; - struct blockvector *bl; - - if (symtab == 0) /* if no symtab specified by caller */ - { - /* First search all symtabs for one whose file contains our pc */ - symtab = find_pc_sect_symtab (pc, section); - if (symtab == 0) - return 0; - } - - bl = BLOCKVECTOR (symtab); - - /* Then search that symtab for the smallest block that wins. */ /* If we have an addrmap mapping code addresses to blocks, then use that. */ if (BLOCKVECTOR_MAP (bl)) - { - b = addrmap_find (BLOCKVECTOR_MAP (bl), pc); - if (b) - { - if (pblock) - *pblock = b; - return bl; - } - else - return 0; - } - + return addrmap_find (BLOCKVECTOR_MAP (bl), pc); /* Otherwise, use binary search to find the last block that starts - before PC. */ - bot = 0; + before PC. + Note: GLOBAL_BLOCK is block 0, STATIC_BLOCK is block 1. + They both have the same START,END values. + Historically this code would choose STATIC_BLOCK over GLOBAL_BLOCK but the + fact that this choice was made was subtle, now we make it explicit. */ + gdb_assert (BLOCKVECTOR_NBLOCKS (bl) >= 2); + bot = STATIC_BLOCK; top = BLOCKVECTOR_NBLOCKS (bl); while (top - bot > 1) @@ -161,18 +139,55 @@ blockvector_for_pc_sect (CORE_ADDR pc, struct obj_section *section, /* Now search backward for a block that ends after PC. */ - while (bot >= 0) + while (bot >= STATIC_BLOCK) { b = BLOCKVECTOR_BLOCK (bl, bot); if (BLOCK_END (b) > pc) - { - if (pblock) - *pblock = b; - return bl; - } + return b; bot--; } - return 0; + + return NULL; +} + +/* 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 + don't pass this information back to the caller. */ + +struct blockvector * +blockvector_for_pc_sect (CORE_ADDR pc, struct obj_section *section, + struct block **pblock, struct symtab *symtab) +{ + struct blockvector *bl; + struct block *b; + + if (symtab == 0) /* if no symtab specified by caller */ + { + /* First search all symtabs for one whose file contains our pc */ + symtab = find_pc_sect_symtab (pc, section); + if (symtab == 0) + return 0; + } + + bl = BLOCKVECTOR (symtab); + + /* Then search that symtab for the smallest block that wins. */ + b = find_block_in_blockvector (bl, pc); + if (b == NULL) + return NULL; + + if (pblock) + *pblock = b; + return bl; +} + +/* Return true if the blockvector BV contains PC, false otherwise. */ + +int +blockvector_contains_pc (struct blockvector *bv, CORE_ADDR pc) +{ + return find_block_in_blockvector (bv, pc) != NULL; } /* Return call_site for specified PC in GDBARCH. PC must match exactly, it @@ -369,3 +384,311 @@ allocate_block (struct obstack *obstack) return bl; } + +/* Allocate a global block. */ + +struct block * +allocate_global_block (struct obstack *obstack) +{ + struct global_block *bl = OBSTACK_ZALLOC (obstack, struct global_block); + + return &bl->block; +} + +/* Set the symtab of the global block. */ + +void +set_block_symtab (struct block *block, struct symtab *symtab) +{ + struct global_block *gb; + + gdb_assert (BLOCK_SUPERBLOCK (block) == NULL); + gb = (struct global_block *) block; + gdb_assert (gb->symtab == NULL); + gb->symtab = symtab; +} + +/* Return the symtab of the global block. */ + +static struct symtab * +get_block_symtab (const struct block *block) +{ + struct global_block *gb; + + gdb_assert (BLOCK_SUPERBLOCK (block) == NULL); + gb = (struct global_block *) block; + gdb_assert (gb->symtab != NULL); + return gb->symtab; +} + + + +/* Initialize a block iterator, either to iterate over a single block, + or, for static and global blocks, all the included symtabs as + well. */ + +static void +initialize_block_iterator (const struct block *block, + struct block_iterator *iter) +{ + enum block_enum which; + struct symtab *symtab; + + iter->idx = -1; + + if (BLOCK_SUPERBLOCK (block) == NULL) + { + which = GLOBAL_BLOCK; + symtab = get_block_symtab (block); + } + else if (BLOCK_SUPERBLOCK (BLOCK_SUPERBLOCK (block)) == NULL) + { + which = STATIC_BLOCK; + symtab = get_block_symtab (BLOCK_SUPERBLOCK (block)); + } + else + { + iter->d.block = block; + /* A signal value meaning that we're iterating over a single + block. */ + iter->which = FIRST_LOCAL_BLOCK; + return; + } + + /* If this is an included symtab, find the canonical includer and + use it instead. */ + while (symtab->user != NULL) + symtab = symtab->user; + + /* Putting this check here simplifies the logic of the iterator + functions. If there are no included symtabs, we only need to + search a single block, so we might as well just do that + directly. */ + if (symtab->includes == NULL) + { + iter->d.block = block; + /* A signal value meaning that we're iterating over a single + block. */ + iter->which = FIRST_LOCAL_BLOCK; + } + else + { + iter->d.symtab = symtab; + iter->which = which; + } +} + +/* A helper function that finds the current symtab over whose static + or global block we should iterate. */ + +static struct symtab * +find_iterator_symtab (struct block_iterator *iterator) +{ + if (iterator->idx == -1) + return iterator->d.symtab; + return iterator->d.symtab->includes[iterator->idx]; +} + +/* Perform a single step for a plain block iterator, iterating across + symbol tables as needed. Returns the next symbol, or NULL when + iteration is complete. */ + +static struct symbol * +block_iterator_step (struct block_iterator *iterator, int first) +{ + struct symbol *sym; + + gdb_assert (iterator->which != FIRST_LOCAL_BLOCK); + + while (1) + { + if (first) + { + struct symtab *symtab = find_iterator_symtab (iterator); + const struct block *block; + + /* Iteration is complete. */ + if (symtab == NULL) + return NULL; + + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), iterator->which); + sym = dict_iterator_first (BLOCK_DICT (block), &iterator->dict_iter); + } + else + sym = dict_iterator_next (&iterator->dict_iter); + + if (sym != NULL) + return sym; + + /* We have finished iterating the appropriate block of one + symtab. Now advance to the next symtab and begin iteration + there. */ + ++iterator->idx; + first = 1; + } +} + +/* See block.h. */ + +struct symbol * +block_iterator_first (const struct block *block, + struct block_iterator *iterator) +{ + initialize_block_iterator (block, iterator); + + if (iterator->which == FIRST_LOCAL_BLOCK) + return dict_iterator_first (block->dict, &iterator->dict_iter); + + return block_iterator_step (iterator, 1); +} + +/* See block.h. */ + +struct symbol * +block_iterator_next (struct block_iterator *iterator) +{ + if (iterator->which == FIRST_LOCAL_BLOCK) + return dict_iterator_next (&iterator->dict_iter); + + return block_iterator_step (iterator, 0); +} + +/* Perform a single step for a "name" block iterator, iterating across + symbol tables as needed. Returns the next symbol, or NULL when + iteration is complete. */ + +static struct symbol * +block_iter_name_step (struct block_iterator *iterator, const char *name, + int first) +{ + struct symbol *sym; + + gdb_assert (iterator->which != FIRST_LOCAL_BLOCK); + + while (1) + { + if (first) + { + struct symtab *symtab = find_iterator_symtab (iterator); + const struct block *block; + + /* Iteration is complete. */ + if (symtab == NULL) + return NULL; + + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), iterator->which); + sym = dict_iter_name_first (BLOCK_DICT (block), name, + &iterator->dict_iter); + } + else + sym = dict_iter_name_next (name, &iterator->dict_iter); + + if (sym != NULL) + return sym; + + /* We have finished iterating the appropriate block of one + symtab. Now advance to the next symtab and begin iteration + there. */ + ++iterator->idx; + first = 1; + } +} + +/* See block.h. */ + +struct symbol * +block_iter_name_first (const struct block *block, + const char *name, + struct block_iterator *iterator) +{ + initialize_block_iterator (block, iterator); + + if (iterator->which == FIRST_LOCAL_BLOCK) + return dict_iter_name_first (block->dict, name, &iterator->dict_iter); + + return block_iter_name_step (iterator, name, 1); +} + +/* See block.h. */ + +struct symbol * +block_iter_name_next (const char *name, struct block_iterator *iterator) +{ + if (iterator->which == FIRST_LOCAL_BLOCK) + return dict_iter_name_next (name, &iterator->dict_iter); + + return block_iter_name_step (iterator, name, 0); +} + +/* Perform a single step for a "match" block iterator, iterating + across symbol tables as needed. Returns the next symbol, or NULL + when iteration is complete. */ + +static struct symbol * +block_iter_match_step (struct block_iterator *iterator, + const char *name, + symbol_compare_ftype *compare, + int first) +{ + struct symbol *sym; + + gdb_assert (iterator->which != FIRST_LOCAL_BLOCK); + + while (1) + { + if (first) + { + struct symtab *symtab = find_iterator_symtab (iterator); + const struct block *block; + + /* Iteration is complete. */ + if (symtab == NULL) + return NULL; + + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), iterator->which); + sym = dict_iter_match_first (BLOCK_DICT (block), name, + compare, &iterator->dict_iter); + } + else + sym = dict_iter_match_next (name, compare, &iterator->dict_iter); + + if (sym != NULL) + return sym; + + /* We have finished iterating the appropriate block of one + symtab. Now advance to the next symtab and begin iteration + there. */ + ++iterator->idx; + first = 1; + } +} + +/* See block.h. */ + +struct symbol * +block_iter_match_first (const struct block *block, + const char *name, + symbol_compare_ftype *compare, + struct block_iterator *iterator) +{ + initialize_block_iterator (block, iterator); + + if (iterator->which == FIRST_LOCAL_BLOCK) + return dict_iter_match_first (block->dict, name, compare, + &iterator->dict_iter); + + return block_iter_match_step (iterator, name, compare, 1); +} + +/* See block.h. */ + +struct symbol * +block_iter_match_next (const char *name, + symbol_compare_ftype *compare, + struct block_iterator *iterator) +{ + if (iterator->which == FIRST_LOCAL_BLOCK) + return dict_iter_match_next (name, compare, &iterator->dict_iter); + + return block_iter_match_step (iterator, name, compare, 0); +} diff --git a/contrib/gdb-7/gdb/block.h b/contrib/gdb-7/gdb/block.h index 2cbcc1b847..02e7e8bb85 100644 --- a/contrib/gdb-7/gdb/block.h +++ b/contrib/gdb-7/gdb/block.h @@ -1,6 +1,6 @@ /* Code dealing with blocks for GDB. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -20,6 +20,8 @@ #ifndef BLOCK_H #define BLOCK_H +#include "dictionary.h" + /* Opaque declarations. */ struct symbol; @@ -27,7 +29,6 @@ struct symtab; struct block_namespace_info; struct using_direct; struct obstack; -struct dictionary; struct addrmap; /* All of the name-scope contours of the program @@ -98,6 +99,21 @@ struct block language_specific; }; +/* The global block is singled out so that we can provide a back-link + to the primary symtab. */ + +struct global_block +{ + /* The block. */ + + struct block block; + + /* This holds a pointer to the primary symtab holding this + block. */ + + struct symtab *symtab; +}; + #define BLOCK_START(bl) (bl)->startaddr #define BLOCK_END(bl) (bl)->endaddr #define BLOCK_FUNCTION(bl) (bl)->function @@ -105,13 +121,6 @@ struct block #define BLOCK_DICT(bl) (bl)->dict #define BLOCK_NAMESPACE(bl) (bl)->language_specific.cplus_specific.namespace -/* Macro to loop through all symbols in a block BL, in no particular - order. ITER helps keep track of the iteration, and should be a - struct dict_iterator. SYM points to the current symbol. */ - -#define ALL_BLOCK_SYMBOLS(block, iter, sym) \ - ALL_DICT_SYMBOLS (BLOCK_DICT (block), iter, sym) - struct blockvector { /* Number of blocks in the list. */ @@ -143,6 +152,8 @@ extern struct blockvector *blockvector_for_pc_sect (CORE_ADDR, struct block **, struct symtab *); +extern int blockvector_contains_pc (struct blockvector *bv, CORE_ADDR pc); + extern struct call_site *call_site_for_pc (struct gdbarch *gdbarch, CORE_ADDR pc); @@ -167,4 +178,105 @@ extern const struct block *block_global_block (const struct block *block); extern struct block *allocate_block (struct obstack *obstack); +extern struct block *allocate_global_block (struct obstack *obstack); + +extern void set_block_symtab (struct block *, struct symtab *); + +/* A block iterator. This structure should be treated as though it + were opaque; it is only defined here because we want to support + stack allocation of iterators. */ + +struct block_iterator +{ + /* If we're iterating over a single block, this holds the block. + Otherwise, it holds the canonical symtab. */ + + union + { + struct symtab *symtab; + const struct block *block; + } d; + + /* If we're iterating over a single block, this is always -1. + Otherwise, it holds the index of the current "included" symtab in + the canonical symtab (that is, d.symtab->includes[idx]), with -1 + meaning the canonical symtab itself. */ + + int idx; + + /* Which block, either static or global, to iterate over. If this + is FIRST_LOCAL_BLOCK, then we are iterating over a single block. + This is used to select which field of 'd' is in use. */ + + enum block_enum which; + + /* The underlying dictionary iterator. */ + + struct dict_iterator dict_iter; +}; + +/* Initialize ITERATOR to point at the first symbol in BLOCK, and + return that first symbol, or NULL if BLOCK is empty. */ + +extern struct symbol *block_iterator_first (const struct block *block, + struct block_iterator *iterator); + +/* Advance ITERATOR, and return the next symbol, or NULL if there are + no more symbols. Don't call this if you've previously received + NULL from block_iterator_first or block_iterator_next on this + iteration. */ + +extern struct symbol *block_iterator_next (struct block_iterator *iterator); + +/* Initialize ITERATOR to point at the first symbol in BLOCK whose + SYMBOL_SEARCH_NAME is NAME (as tested using strcmp_iw), and return + that first symbol, or NULL if there are no such symbols. */ + +extern struct symbol *block_iter_name_first (const struct block *block, + const char *name, + struct block_iterator *iterator); + +/* Advance ITERATOR to point at the next symbol in BLOCK whose + SYMBOL_SEARCH_NAME is NAME (as tested using strcmp_iw), or NULL if + there are no more such symbols. Don't call this if you've + previously received NULL from block_iterator_first or + block_iterator_next on this iteration. And don't call it unless + ITERATOR was created by a previous call to block_iter_name_first + with the same NAME. */ + +extern struct symbol *block_iter_name_next (const char *name, + struct block_iterator *iterator); + +/* Initialize ITERATOR to point at the first symbol in BLOCK whose + SYMBOL_SEARCH_NAME is NAME, as tested using COMPARE (which must use + the same conventions as strcmp_iw and be compatible with any + block hashing function), and return that first symbol, or NULL + if there are no such symbols. */ + +extern struct symbol *block_iter_match_first (const struct block *block, + const char *name, + symbol_compare_ftype *compare, + struct block_iterator *iterator); + +/* Advance ITERATOR to point at the next symbol in BLOCK whose + SYMBOL_SEARCH_NAME is NAME, as tested using COMPARE (see + block_iter_match_first), or NULL if there are no more such symbols. + Don't call this if you've previously received NULL from + block_iterator_match_first or block_iterator_match_next on this + iteration. And don't call it unless ITERATOR was created by a + previous call to block_iter_match_first with the same NAME and COMPARE. */ + +extern struct symbol *block_iter_match_next (const char *name, + symbol_compare_ftype *compare, + struct block_iterator *iterator); + +/* Macro to loop through all symbols in a block BL, in no particular + order. ITER helps keep track of the iteration, and should be a + struct block_iterator. SYM points to the current symbol. */ + +#define ALL_BLOCK_SYMBOLS(block, iter, sym) \ + for ((sym) = block_iterator_first ((block), &(iter)); \ + (sym); \ + (sym) = block_iterator_next (&(iter))) + #endif /* BLOCK_H */ diff --git a/contrib/gdb-7/gdb/blockframe.c b/contrib/gdb-7/gdb/blockframe.c index 38973667cd..d5787f1e2f 100644 --- a/contrib/gdb-7/gdb/blockframe.c +++ b/contrib/gdb-7/gdb/blockframe.c @@ -1,7 +1,7 @@ /* Get info from stack frames; convert between frames, blocks, functions and pc values. - Copyright (C) 1986-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -159,7 +159,7 @@ find_pc_function (CORE_ADDR pc) static CORE_ADDR cache_pc_function_low = 0; static CORE_ADDR cache_pc_function_high = 0; -static char *cache_pc_function_name = 0; +static const char *cache_pc_function_name = 0; static struct obj_section *cache_pc_function_section = NULL; static int cache_pc_function_is_gnu_ifunc = 0; @@ -190,7 +190,7 @@ clear_pc_function_cache (void) /* Backward compatibility, no section argument. */ int -find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, char **name, +find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, const char **name, CORE_ADDR *address, CORE_ADDR *endaddr, int *is_gnu_ifunc_p) { @@ -346,29 +346,27 @@ find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, char **name, is omitted here for backward API compatibility. */ int -find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address, +find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address, CORE_ADDR *endaddr) { return find_pc_partial_function_gnu_ifunc (pc, name, address, endaddr, NULL); } -/* Return the innermost stack frame executing inside of BLOCK, or NULL - if there is no such frame. If BLOCK is NULL, just return NULL. */ +/* Return the innermost stack frame that is executing inside of BLOCK and is + at least as old as the selected frame. Return NULL if there is no + such frame. If BLOCK is NULL, just return NULL. */ struct frame_info * block_innermost_frame (const struct block *block) { struct frame_info *frame; - CORE_ADDR start; - CORE_ADDR end; if (block == NULL) return NULL; - start = BLOCK_START (block); - end = BLOCK_END (block); - - frame = get_current_frame (); + frame = get_selected_frame_if_set (); + if (frame == NULL) + frame = get_current_frame (); while (frame != NULL) { struct block *frame_block = get_frame_block (frame, NULL); diff --git a/contrib/gdb-7/gdb/break-catch-sig.c b/contrib/gdb-7/gdb/break-catch-sig.c new file mode 100644 index 0000000000..379965d22a --- /dev/null +++ b/contrib/gdb-7/gdb/break-catch-sig.c @@ -0,0 +1,507 @@ +/* Everything about signal catchpoints, for GDB. + + Copyright (C) 2011-2013 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 "arch-utils.h" +#include +#include "breakpoint.h" +#include "gdbcmd.h" +#include "inferior.h" +#include "annotate.h" +#include "valprint.h" +#include "cli/cli-utils.h" +#include "completer.h" +#include "gdb_obstack.h" + +#define INTERNAL_SIGNAL(x) ((x) == GDB_SIGNAL_TRAP || (x) == GDB_SIGNAL_INT) + +typedef enum gdb_signal gdb_signal_type; + +DEF_VEC_I (gdb_signal_type); + +/* An instance of this type is used to represent a signal catchpoint. + It includes a "struct breakpoint" as a kind of base class; users + downcast to "struct breakpoint *" when needed. A breakpoint is + really of this type iff its ops pointer points to + SIGNAL_CATCHPOINT_OPS. */ + +struct signal_catchpoint +{ + /* The base class. */ + + struct breakpoint base; + + /* Signal numbers used for the 'catch signal' feature. If no signal + has been specified for filtering, its value is NULL. Otherwise, + it holds a list of all signals to be caught. */ + + VEC (gdb_signal_type) *signals_to_be_caught; + + /* If SIGNALS_TO_BE_CAUGHT is NULL, then all "ordinary" signals are + caught. If CATCH_ALL is non-zero, then internal signals are + caught as well. If SIGNALS_TO_BE_CAUGHT is non-NULL, then this + field is ignored. */ + + int catch_all; +}; + +/* The breakpoint_ops structure to be used in signal catchpoints. */ + +static struct breakpoint_ops signal_catchpoint_ops; + +/* Count of each signal. */ + +static unsigned int *signal_catch_counts; + + + +/* A convenience wrapper for gdb_signal_to_name that returns the + integer value if the name is not known. */ + +static const char * +signal_to_name_or_int (enum gdb_signal sig) +{ + const char *result = gdb_signal_to_name (sig); + + if (strcmp (result, "?") == 0) + result = plongest (sig); + + return result; +} + + + +/* Implement the "dtor" breakpoint_ops method for signal + catchpoints. */ + +static void +signal_catchpoint_dtor (struct breakpoint *b) +{ + struct signal_catchpoint *c = (struct signal_catchpoint *) b; + + VEC_free (gdb_signal_type, c->signals_to_be_caught); + + base_breakpoint_ops.dtor (b); +} + +/* Implement the "insert_location" breakpoint_ops method for signal + catchpoints. */ + +static int +signal_catchpoint_insert_location (struct bp_location *bl) +{ + struct signal_catchpoint *c = (void *) bl->owner; + int i; + + if (c->signals_to_be_caught != NULL) + { + gdb_signal_type iter; + + for (i = 0; + VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); + i++) + ++signal_catch_counts[iter]; + } + else + { + for (i = 0; i < GDB_SIGNAL_LAST; ++i) + { + if (c->catch_all || !INTERNAL_SIGNAL (i)) + ++signal_catch_counts[i]; + } + } + + signal_catch_update (signal_catch_counts); + + return 0; +} + +/* Implement the "remove_location" breakpoint_ops method for signal + catchpoints. */ + +static int +signal_catchpoint_remove_location (struct bp_location *bl) +{ + struct signal_catchpoint *c = (void *) bl->owner; + int i; + + if (c->signals_to_be_caught != NULL) + { + gdb_signal_type iter; + + for (i = 0; + VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); + i++) + { + gdb_assert (signal_catch_counts[iter] > 0); + --signal_catch_counts[iter]; + } + } + else + { + for (i = 0; i < GDB_SIGNAL_LAST; ++i) + { + if (c->catch_all || !INTERNAL_SIGNAL (i)) + { + gdb_assert (signal_catch_counts[i] > 0); + --signal_catch_counts[i]; + } + } + } + + signal_catch_update (signal_catch_counts); + + return 0; +} + +/* Implement the "breakpoint_hit" breakpoint_ops method for signal + catchpoints. */ + +static int +signal_catchpoint_breakpoint_hit (const struct bp_location *bl, + struct address_space *aspace, + CORE_ADDR bp_addr, + const struct target_waitstatus *ws) +{ + const struct signal_catchpoint *c = (void *) bl->owner; + gdb_signal_type signal_number; + + if (ws->kind != TARGET_WAITKIND_STOPPED) + return 0; + + signal_number = ws->value.sig; + + /* If we are catching specific signals in this breakpoint, then we + must guarantee that the called signal is the same signal we are + catching. */ + if (c->signals_to_be_caught) + { + int i; + gdb_signal_type iter; + + for (i = 0; + VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); + i++) + if (signal_number == iter) + break; + /* Not the same. */ + if (!iter) + return 0; + } + + return c->catch_all || !INTERNAL_SIGNAL (signal_number); +} + +/* Implement the "print_it" breakpoint_ops method for signal + catchpoints. */ + +static enum print_stop_action +signal_catchpoint_print_it (bpstat bs) +{ + struct breakpoint *b = bs->breakpoint_at; + ptid_t ptid; + struct target_waitstatus last; + const char *signal_name; + + get_last_target_status (&ptid, &last); + + signal_name = signal_to_name_or_int (last.value.sig); + + annotate_catchpoint (b->number); + + printf_filtered (_("\nCatchpoint %d (signal %s), "), b->number, signal_name); + + return PRINT_SRC_AND_LOC; +} + +/* Implement the "print_one" breakpoint_ops method for signal + catchpoints. */ + +static void +signal_catchpoint_print_one (struct breakpoint *b, + struct bp_location **last_loc) +{ + struct signal_catchpoint *c = (void *) b; + struct value_print_options opts; + struct ui_out *uiout = current_uiout; + + 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); + + if (c->signals_to_be_caught + && VEC_length (gdb_signal_type, c->signals_to_be_caught) > 1) + ui_out_text (uiout, "signals \""); + else + ui_out_text (uiout, "signal \""); + + if (c->signals_to_be_caught) + { + int i; + gdb_signal_type iter; + struct obstack text; + struct cleanup *cleanup; + + obstack_init (&text); + cleanup = make_cleanup_obstack_free (&text); + + for (i = 0; + VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); + i++) + { + const char *name = signal_to_name_or_int (iter); + + if (i > 0) + obstack_grow (&text, " ", 1); + obstack_grow (&text, name, strlen (name)); + } + obstack_grow (&text, "", 1); + ui_out_field_string (uiout, "what", obstack_base (&text)); + do_cleanups (cleanup); + } + else + ui_out_field_string (uiout, "what", + c->catch_all ? "" : ""); + ui_out_text (uiout, "\" "); + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "catch-type", "signal"); +} + +/* Implement the "print_mention" breakpoint_ops method for signal + catchpoints. */ + +static void +signal_catchpoint_print_mention (struct breakpoint *b) +{ + struct signal_catchpoint *c = (void *) b; + + if (c->signals_to_be_caught) + { + int i; + gdb_signal_type iter; + + if (VEC_length (gdb_signal_type, c->signals_to_be_caught) > 1) + printf_filtered (_("Catchpoint %d (signals"), b->number); + else + printf_filtered (_("Catchpoint %d (signal"), b->number); + + for (i = 0; + VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); + i++) + { + const char *name = signal_to_name_or_int (iter); + + printf_filtered (" %s", name); + } + printf_filtered (")"); + } + else if (c->catch_all) + printf_filtered (_("Catchpoint %d (any signal)"), b->number); + else + printf_filtered (_("Catchpoint %d (standard signals)"), b->number); +} + +/* Implement the "print_recreate" breakpoint_ops method for signal + catchpoints. */ + +static void +signal_catchpoint_print_recreate (struct breakpoint *b, struct ui_file *fp) +{ + struct signal_catchpoint *c = (void *) b; + + fprintf_unfiltered (fp, "catch signal"); + + if (c->signals_to_be_caught) + { + int i; + gdb_signal_type iter; + + for (i = 0; + VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); + i++) + fprintf_unfiltered (fp, " %s", signal_to_name_or_int (iter)); + } + else if (c->catch_all) + fprintf_unfiltered (fp, " all"); +} + +/* Implement the "explains_signal" breakpoint_ops method for signal + catchpoints. */ + +static enum bpstat_signal_value +signal_catchpoint_explains_signal (struct breakpoint *b, enum gdb_signal sig) +{ + return BPSTAT_SIGNAL_PASS; +} + +/* Create a new signal catchpoint. TEMPFLAG is true if this should be + a temporary catchpoint. FILTER is the list of signals to catch; it + can be NULL, meaning all signals. CATCH_ALL is a flag indicating + whether signals used internally by gdb should be caught; it is only + valid if FILTER is NULL. If FILTER is NULL and CATCH_ALL is zero, + then internal signals like SIGTRAP are not caught. */ + +static void +create_signal_catchpoint (int tempflag, VEC (gdb_signal_type) *filter, + int catch_all) +{ + struct signal_catchpoint *c; + struct gdbarch *gdbarch = get_current_arch (); + + c = XNEW (struct signal_catchpoint); + init_catchpoint (&c->base, gdbarch, tempflag, NULL, &signal_catchpoint_ops); + c->signals_to_be_caught = filter; + c->catch_all = catch_all; + + install_breakpoint (0, &c->base, 1); +} + + +/* Splits the argument using space as delimiter. Returns an xmalloc'd + filter list, or NULL if no filtering is required. */ + +static VEC (gdb_signal_type) * +catch_signal_split_args (char *arg, int *catch_all) +{ + VEC (gdb_signal_type) *result = NULL; + struct cleanup *cleanup = make_cleanup (VEC_cleanup (gdb_signal_type), + &result); + int first = 1; + + while (*arg != '\0') + { + int num; + gdb_signal_type signal_number; + char *one_arg, *endptr; + struct cleanup *inner_cleanup; + + one_arg = extract_arg (&arg); + if (one_arg == NULL) + break; + inner_cleanup = make_cleanup (xfree, one_arg); + + /* Check for the special flag "all". */ + if (strcmp (one_arg, "all") == 0) + { + arg = skip_spaces (arg); + if (*arg != '\0' || !first) + error (_("'all' cannot be caught with other signals")); + *catch_all = 1; + gdb_assert (result == NULL); + do_cleanups (inner_cleanup); + discard_cleanups (cleanup); + return NULL; + } + + first = 0; + + /* Check if the user provided a signal name or a number. */ + num = (int) strtol (one_arg, &endptr, 0); + if (*endptr == '\0') + signal_number = gdb_signal_from_command (num); + else + { + signal_number = gdb_signal_from_name (one_arg); + if (signal_number == GDB_SIGNAL_UNKNOWN) + error (_("Unknown signal name '%s'."), one_arg); + } + + VEC_safe_push (gdb_signal_type, result, signal_number); + do_cleanups (inner_cleanup); + } + + discard_cleanups (cleanup); + return result; +} + +/* Implement the "catch signal" command. */ + +static void +catch_signal_command (char *arg, int from_tty, + struct cmd_list_element *command) +{ + int tempflag, catch_all = 0; + VEC (gdb_signal_type) *filter; + + tempflag = get_cmd_context (command) == CATCH_TEMPORARY; + + arg = skip_spaces (arg); + + /* The allowed syntax is: + catch signal + catch signal [ ... ] + + Let's check if there's a signal name. */ + + if (arg != NULL) + filter = catch_signal_split_args (arg, &catch_all); + else + filter = NULL; + + create_signal_catchpoint (tempflag, filter, catch_all); +} + +static void +initialize_signal_catchpoint_ops (void) +{ + struct breakpoint_ops *ops; + + initialize_breakpoint_ops (); + + ops = &signal_catchpoint_ops; + *ops = base_breakpoint_ops; + ops->dtor = signal_catchpoint_dtor; + ops->insert_location = signal_catchpoint_insert_location; + ops->remove_location = signal_catchpoint_remove_location; + ops->breakpoint_hit = signal_catchpoint_breakpoint_hit; + ops->print_it = signal_catchpoint_print_it; + ops->print_one = signal_catchpoint_print_one; + ops->print_mention = signal_catchpoint_print_mention; + ops->print_recreate = signal_catchpoint_print_recreate; + ops->explains_signal = signal_catchpoint_explains_signal; +} + +initialize_file_ftype _initialize_break_catch_sig; + +void +_initialize_break_catch_sig (void) +{ + initialize_signal_catchpoint_ops (); + + signal_catch_counts = XCNEWVEC (unsigned int, GDB_SIGNAL_LAST); + + add_catch_command ("signal", _("\ +Catch signals by their names and/or numbers.\n\ +Usage: catch signal [[NAME|NUMBER] [NAME|NUMBER]...|all]\n\ +Arguments say which signals to catch. If no arguments\n\ +are given, every \"normal\" signal will be caught.\n\ +The argument \"all\" means to also catch signals used by GDB.\n\ +Arguments, if given, should be one or more signal names\n\ +(if your system supports that), or signal numbers."), + catch_signal_command, + signal_completer, + CATCH_PERMANENT, + CATCH_TEMPORARY); +} diff --git a/contrib/gdb-7/gdb/breakpoint.c b/contrib/gdb-7/gdb/breakpoint.c index 5a8c29ce28..97ba7be925 100644 --- a/contrib/gdb-7/gdb/breakpoint.c +++ b/contrib/gdb-7/gdb/breakpoint.c @@ -1,6 +1,6 @@ /* Everything about breakpoints, for GDB. - Copyright (C) 1986-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -56,16 +56,21 @@ #include "memattr.h" #include "ada-lang.h" #include "top.h" -#include "wrapper.h" #include "valprint.h" #include "jit.h" #include "xml-syscall.h" #include "parser-defs.h" +#include "gdb_regex.h" +#include "probe.h" #include "cli/cli-utils.h" #include "continuations.h" #include "stack.h" #include "skip.h" -#include "record.h" +#include "gdb_regex.h" +#include "ax-gdb.h" +#include "dummy-frame.h" + +#include "format.h" /* readline include files */ #include "readline/readline.h" @@ -77,12 +82,21 @@ #include "mi/mi-common.h" #include "python/python.h" +/* Enums for exception-handling support. */ +enum exception_event_kind +{ + EX_EVENT_THROW, + EX_EVENT_CATCH +}; + /* Prototypes for local functions. */ static void enable_delete_command (char *, int); static void enable_once_command (char *, int); +static void enable_count_command (char *, int); + static void disable_command (char *, int); static void enable_command (char *, int); @@ -97,6 +111,23 @@ static int breakpoint_re_set_one (void *); static void breakpoint_re_set_default (struct breakpoint *); +static void create_sals_from_address_default (char **, + struct linespec_result *, + enum bptype, char *, + char **); + +static void create_breakpoints_sal_default (struct gdbarch *, + struct linespec_result *, + struct linespec_sals *, + char *, char *, enum bptype, + enum bpdisp, int, int, + int, + const struct breakpoint_ops *, + int, int, int, unsigned); + +static void decode_linespec_default (struct breakpoint *, char **, + struct symtabs_and_lines *); + static void clear_command (char *, int); static void catch_command (char *, int); @@ -190,7 +221,8 @@ static void hbreak_command (char *, int); static void thbreak_command (char *, int); -static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp); +static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp, + int count); static void stop_command (char *arg, int from_tty); @@ -236,16 +268,20 @@ static void disable_trace_command (char *, int); static void trace_pass_command (char *, int); +static void set_tracepoint_count (int num); + static int is_masked_watchpoint (const struct breakpoint *b); -/* Assuming we're creating a static tracepoint, does S look like a - static tracepoint marker spec ("-m MARKER_ID")? */ -#define is_marker_spec(s) \ - (s != NULL && strncmp (s, "-m", 2) == 0 && ((s)[2] == ' ' || (s)[2] == '\t')) +static struct bp_location **get_first_locp_gte_addr (CORE_ADDR address); + +/* Return 1 if B refers to a static tracepoint set by marker ("-m"), zero + otherwise. */ + +static int strace_marker_p (struct breakpoint *b); /* The abstract base class all breakpoint_ops structures inherit from. */ -static struct breakpoint_ops base_breakpoint_ops; +struct breakpoint_ops base_breakpoint_ops; /* The breakpoint_ops structure to be inherited by all breakpoint_ops that are implemented on top of software or hardware breakpoints @@ -258,10 +294,58 @@ static struct breakpoint_ops internal_breakpoint_ops; /* Momentary breakpoints class type. */ static struct breakpoint_ops momentary_breakpoint_ops; +/* Momentary breakpoints for bp_longjmp and bp_exception class type. */ +static struct breakpoint_ops longjmp_breakpoint_ops; + /* The breakpoint_ops structure to be used in regular user created breakpoints. */ struct breakpoint_ops bkpt_breakpoint_ops; +/* Breakpoints set on probes. */ +static struct breakpoint_ops bkpt_probe_breakpoint_ops; + +/* Dynamic printf class type. */ +static struct breakpoint_ops dprintf_breakpoint_ops; + +/* The style in which to perform a dynamic printf. This is a user + option because different output options have different tradeoffs; + if GDB does the printing, there is better error handling if there + is a problem with any of the arguments, but using an inferior + function lets you have special-purpose printers and sending of + output to the same place as compiled-in print functions. */ + +static const char dprintf_style_gdb[] = "gdb"; +static const char dprintf_style_call[] = "call"; +static const char dprintf_style_agent[] = "agent"; +static const char *const dprintf_style_enums[] = { + dprintf_style_gdb, + dprintf_style_call, + dprintf_style_agent, + NULL +}; +static const char *dprintf_style = dprintf_style_gdb; + +/* The function to use for dynamic printf if the preferred style is to + call into the inferior. The value is simply a string that is + copied into the command, so it can be anything that GDB can + evaluate to a callable address, not necessarily a function name. */ + +static char *dprintf_function = ""; + +/* The channel to use for dynamic printf if the preferred style is to + call into the inferior; if a nonempty string, it will be passed to + the call as the first argument, with the format string as the + second. As with the dprintf function, this can be anything that + GDB knows how to evaluate, so in addition to common choices like + "stderr", this could be an app-specific expression like + "mystreams[curlogger]". */ + +static char *dprintf_channel = ""; + +/* True if dprintf commands should continue to operate even if GDB + has disconnected. */ +static int disconnected_dprintf = 1; + /* A reference-counted struct command_line. This lets multiple breakpoints share a single command list. */ struct counted_command_line @@ -348,21 +432,13 @@ show_automatic_hardware_breakpoints (struct ui_file *file, int from_tty, will remove breakpoints upon stop. If auto, GDB will behave as ON if in non-stop mode, and as OFF if all-stop mode.*/ -static const char always_inserted_auto[] = "auto"; -static const char always_inserted_on[] = "on"; -static const char always_inserted_off[] = "off"; -static const char *always_inserted_enums[] = { - always_inserted_auto, - always_inserted_off, - always_inserted_on, - NULL -}; -static const char *always_inserted_mode = always_inserted_auto; +static enum auto_boolean always_inserted_mode = AUTO_BOOLEAN_AUTO; + static void show_always_inserted_mode (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - if (always_inserted_mode == always_inserted_auto) + if (always_inserted_mode == AUTO_BOOLEAN_AUTO) fprintf_filtered (file, _("Always inserted breakpoint " "mode is %s (currently %s).\n"), @@ -376,9 +452,66 @@ show_always_inserted_mode (struct ui_file *file, int from_tty, int breakpoints_always_inserted_mode (void) { - return ((always_inserted_mode == always_inserted_on - || (always_inserted_mode == always_inserted_auto && non_stop)) - && !RECORD_IS_USED); + return (always_inserted_mode == AUTO_BOOLEAN_TRUE + || (always_inserted_mode == AUTO_BOOLEAN_AUTO && non_stop)); +} + +static const char condition_evaluation_both[] = "host or target"; + +/* Modes for breakpoint condition evaluation. */ +static const char condition_evaluation_auto[] = "auto"; +static const char condition_evaluation_host[] = "host"; +static const char condition_evaluation_target[] = "target"; +static const char *const condition_evaluation_enums[] = { + condition_evaluation_auto, + condition_evaluation_host, + condition_evaluation_target, + NULL +}; + +/* Global that holds the current mode for breakpoint condition evaluation. */ +static const char *condition_evaluation_mode_1 = condition_evaluation_auto; + +/* Global that we use to display information to the user (gets its value from + condition_evaluation_mode_1. */ +static const char *condition_evaluation_mode = condition_evaluation_auto; + +/* Translate a condition evaluation mode MODE into either "host" + or "target". This is used mostly to translate from "auto" to the + real setting that is being used. It returns the translated + evaluation mode. */ + +static const char * +translate_condition_evaluation_mode (const char *mode) +{ + if (mode == condition_evaluation_auto) + { + if (target_supports_evaluation_of_breakpoint_conditions ()) + return condition_evaluation_target; + else + return condition_evaluation_host; + } + else + return mode; +} + +/* Discovers what condition_evaluation_auto translates to. */ + +static const char * +breakpoint_condition_evaluation_mode (void) +{ + return translate_condition_evaluation_mode (condition_evaluation_mode); +} + +/* Return true if GDB should evaluate breakpoint conditions or false + otherwise. */ + +static int +gdb_evaluates_breakpoint_condition_p (void) +{ + const char *mode = breakpoint_condition_evaluation_mode (); + + return (mode == condition_evaluation_host); } void _initialize_breakpoint (void); @@ -412,6 +545,20 @@ int target_exact_watchpoints = 0; BP_TMP < bp_location + bp_location_count && (B = *BP_TMP); \ BP_TMP++) +/* Iterates through locations with address ADDRESS for the currently selected + program space. BP_LOCP_TMP points to each object. BP_LOCP_START points + to where the loop should start from. + If BP_LOCP_START is a NULL pointer, the macro automatically seeks the + appropriate location to start with. */ + +#define ALL_BP_LOCATIONS_AT_ADDR(BP_LOCP_TMP, BP_LOCP_START, ADDRESS) \ + for (BP_LOCP_START = BP_LOCP_START == NULL ? get_first_locp_gte_addr (ADDRESS) : BP_LOCP_START, \ + BP_LOCP_TMP = BP_LOCP_START; \ + BP_LOCP_START \ + && (BP_LOCP_TMP < bp_location + bp_location_count \ + && (*BP_LOCP_TMP)->address == ADDRESS); \ + BP_LOCP_TMP++) + /* Iterator for tracepoints only. */ #define ALL_TRACEPOINTS(B) \ @@ -595,6 +742,178 @@ get_breakpoint (int num) +/* Mark locations as "conditions have changed" in case the target supports + evaluating conditions on its side. */ + +static void +mark_breakpoint_modified (struct breakpoint *b) +{ + struct bp_location *loc; + + /* This is only meaningful if the target is + evaluating conditions and if the user has + opted for condition evaluation on the target's + side. */ + if (gdb_evaluates_breakpoint_condition_p () + || !target_supports_evaluation_of_breakpoint_conditions ()) + return; + + if (!is_breakpoint (b)) + return; + + for (loc = b->loc; loc; loc = loc->next) + loc->condition_changed = condition_modified; +} + +/* Mark location as "conditions have changed" in case the target supports + evaluating conditions on its side. */ + +static void +mark_breakpoint_location_modified (struct bp_location *loc) +{ + /* This is only meaningful if the target is + evaluating conditions and if the user has + opted for condition evaluation on the target's + side. */ + if (gdb_evaluates_breakpoint_condition_p () + || !target_supports_evaluation_of_breakpoint_conditions ()) + + return; + + if (!is_breakpoint (loc->owner)) + return; + + loc->condition_changed = condition_modified; +} + +/* Sets the condition-evaluation mode using the static global + condition_evaluation_mode. */ + +static void +set_condition_evaluation_mode (char *args, int from_tty, + struct cmd_list_element *c) +{ + const char *old_mode, *new_mode; + + if ((condition_evaluation_mode_1 == condition_evaluation_target) + && !target_supports_evaluation_of_breakpoint_conditions ()) + { + condition_evaluation_mode_1 = condition_evaluation_mode; + warning (_("Target does not support breakpoint condition evaluation.\n" + "Using host evaluation mode instead.")); + return; + } + + new_mode = translate_condition_evaluation_mode (condition_evaluation_mode_1); + old_mode = translate_condition_evaluation_mode (condition_evaluation_mode); + + /* Flip the switch. Flip it even if OLD_MODE == NEW_MODE as one of the + settings was "auto". */ + condition_evaluation_mode = condition_evaluation_mode_1; + + /* Only update the mode if the user picked a different one. */ + if (new_mode != old_mode) + { + struct bp_location *loc, **loc_tmp; + /* If the user switched to a different evaluation mode, we + need to synch the changes with the target as follows: + + "host" -> "target": Send all (valid) conditions to the target. + "target" -> "host": Remove all the conditions from the target. + */ + + if (new_mode == condition_evaluation_target) + { + /* Mark everything modified and synch conditions with the + target. */ + ALL_BP_LOCATIONS (loc, loc_tmp) + mark_breakpoint_location_modified (loc); + } + else + { + /* Manually mark non-duplicate locations to synch conditions + with the target. We do this to remove all the conditions the + target knows about. */ + ALL_BP_LOCATIONS (loc, loc_tmp) + if (is_breakpoint (loc->owner) && loc->inserted) + loc->needs_update = 1; + } + + /* Do the update. */ + update_global_location_list (1); + } + + return; +} + +/* Shows the current mode of breakpoint condition evaluation. Explicitly shows + what "auto" is translating to. */ + +static void +show_condition_evaluation_mode (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + if (condition_evaluation_mode == condition_evaluation_auto) + fprintf_filtered (file, + _("Breakpoint condition evaluation " + "mode is %s (currently %s).\n"), + value, + breakpoint_condition_evaluation_mode ()); + else + fprintf_filtered (file, _("Breakpoint condition evaluation mode is %s.\n"), + value); +} + +/* A comparison function for bp_location AP and BP that is used by + bsearch. This comparison function only cares about addresses, unlike + the more general bp_location_compare function. */ + +static int +bp_location_compare_addrs (const void *ap, const void *bp) +{ + struct bp_location *a = *(void **) ap; + struct bp_location *b = *(void **) bp; + + if (a->address == b->address) + return 0; + else + return ((a->address > b->address) - (a->address < b->address)); +} + +/* Helper function to skip all bp_locations with addresses + less than ADDRESS. It returns the first bp_location that + is greater than or equal to ADDRESS. If none is found, just + return NULL. */ + +static struct bp_location ** +get_first_locp_gte_addr (CORE_ADDR address) +{ + struct bp_location dummy_loc; + struct bp_location *dummy_locp = &dummy_loc; + struct bp_location **locp_found = NULL; + + /* Initialize the dummy location's address field. */ + memset (&dummy_loc, 0, sizeof (struct bp_location)); + dummy_loc.address = address; + + /* Find a close match to the first location at ADDRESS. */ + locp_found = bsearch (&dummy_locp, bp_location, bp_location_count, + sizeof (struct bp_location **), + bp_location_compare_addrs); + + /* Nothing was found, nothing left to do. */ + if (locp_found == NULL) + return NULL; + + /* We may have found a location that is at ADDRESS but is not the first in the + location's list. Go backwards (if possible) and locate the first one. */ + while ((locp_found - 1) >= bp_location + && (*(locp_found - 1))->address == address) + locp_found--; + + return locp_found; +} + void set_breakpoint_condition (struct breakpoint *b, char *exp, int from_tty) @@ -617,6 +936,10 @@ set_breakpoint_condition (struct breakpoint *b, char *exp, { xfree (loc->cond); loc->cond = NULL; + + /* No need to free the condition agent expression + bytecode (if we have one). We will handle this + when we go through update_global_location_list. */ } } @@ -627,7 +950,7 @@ set_breakpoint_condition (struct breakpoint *b, char *exp, } else { - char *arg = exp; + const char *arg = exp; /* I don't know if it matters whether this is the string the user typed in or the decompiled expression. */ @@ -640,7 +963,7 @@ set_breakpoint_condition (struct breakpoint *b, char *exp, innermost_block = NULL; arg = exp; - w->cond_exp = parse_exp_1 (&arg, 0, 0); + w->cond_exp = parse_exp_1 (&arg, 0, 0, 0); if (*arg) error (_("Junk at end of expression")); w->cond_exp_valid_block = innermost_block; @@ -653,16 +976,62 @@ set_breakpoint_condition (struct breakpoint *b, char *exp, { arg = exp; loc->cond = - parse_exp_1 (&arg, block_for_pc (loc->address), 0); + parse_exp_1 (&arg, loc->address, + block_for_pc (loc->address), 0); if (*arg) error (_("Junk at end of expression")); } } } - breakpoints_changed (); + mark_breakpoint_modified (b); + observer_notify_breakpoint_modified (b); } +/* Completion for the "condition" command. */ + +static VEC (char_ptr) * +condition_completer (struct cmd_list_element *cmd, char *text, char *word) +{ + char *space; + + text = skip_spaces (text); + space = skip_to_space (text); + if (*space == '\0') + { + int len; + struct breakpoint *b; + VEC (char_ptr) *result = NULL; + + if (text[0] == '$') + { + /* We don't support completion of history indices. */ + if (isdigit (text[1])) + return NULL; + return complete_internalvar (&text[1]); + } + + /* We're completing the breakpoint number. */ + len = strlen (text); + + ALL_BREAKPOINTS (b) + { + char number[50]; + + xsnprintf (number, sizeof (number), "%d", b->number); + + if (strncmp (number, text, len) == 0) + VEC_safe_push (char_ptr, result, xstrdup (number)); + } + + return result; + } + + /* We're completing the expression part. */ + text = skip_spaces (space); + return expression_completer (cmd, text, word); +} + /* condition N EXP -- set break condition of breakpoint N to EXP. */ static void @@ -692,6 +1061,10 @@ condition_command (char *arg, int from_tty) error (_("Cannot set a condition where a Python 'stop' " "method has been defined in the breakpoint.")); set_breakpoint_condition (b, p, from_tty); + + if (is_breakpoint (b)) + update_global_location_list (1); + return; } @@ -755,12 +1128,25 @@ validate_commands_for_breakpoint (struct breakpoint *b, { if (is_tracepoint (b)) { - /* We need to verify that each top-level element of commands is - valid for tracepoints, that there's at most one - while-stepping element, and that while-stepping's body has - valid tracing commands excluding nested while-stepping. */ + struct tracepoint *t = (struct tracepoint *) b; struct command_line *c; struct command_line *while_stepping = 0; + + /* Reset the while-stepping step count. The previous commands + might have included a while-stepping action, while the new + ones might not. */ + t->step_count = 0; + + /* We need to verify that each top-level element of commands is + valid for tracepoints, that there's at most one + while-stepping element, and that the while-stepping's body + has valid tracing commands excluding nested while-stepping. + We also need to validate the tracepoint action line in the + context of the tracepoint --- validate_actionline actually + has side effects, like setting the tracepoint's + while-stepping STEP_COUNT, in addition to checking if the + collect/teval actions parse and make sense in the + tracepoint's context. */ for (c = commands; c; c = c->next) { if (c->control_type == while_stepping_control) @@ -778,6 +1164,8 @@ validate_commands_for_breakpoint (struct breakpoint *b, else while_stepping = c; } + + validate_actionline (&c->line, b); } if (while_stepping) { @@ -830,7 +1218,6 @@ breakpoint_set_commands (struct breakpoint *b, decref_counted_command_line (&b->commands); b->commands = alloc_counted_command_line (commands); - breakpoints_changed (); observer_notify_breakpoint_modified (b); } @@ -947,7 +1334,6 @@ do_map_commands_command (struct breakpoint *b, void *data) incref_counted_command_line (info->cmd); decref_counted_command_line (&b->commands); b->commands = info->cmd; - breakpoints_changed (); observer_notify_breakpoint_modified (b); } } @@ -1035,6 +1421,10 @@ bp_location_has_shadow (struct bp_location *bl) /* Update BUF, which is LEN bytes read from the target address MEMADDR, by replacing any memory breakpoints with their shadowed contents. + If READBUF is not NULL, this buffer must not overlap with any of + the breakpoint location's shadow_contents buffers. Otherwise, + a failed assertion internal error will be raised. + The range of shadowed area by each bp_location is: bl->address - bp_location_placed_address_before_address_max up to bl->address + bp_location_shadow_len_after_address_max @@ -1163,6 +1553,12 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf, if (readbuf != NULL) { + /* Verify that the readbuf buffer does not overlap with + the shadow_contents buffer. */ + gdb_assert (bl->target_info.shadow_contents >= readbuf + len + || readbuf >= (bl->target_info.shadow_contents + + bl->target_info.shadow_len)); + /* Update the read buffer with this inserted breakpoint's shadow. */ memcpy (readbuf + bp_addr - memaddr, @@ -1173,7 +1569,7 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf, struct gdbarch *gdbarch = bl->gdbarch; const unsigned char *bp; CORE_ADDR placed_address = bl->target_info.placed_address; - unsigned placed_size = bl->target_info.placed_size; + int placed_size = bl->target_info.placed_size; /* Update the shadow with what we want to write to memory. */ memcpy (bl->target_info.shadow_contents + bptoffset, @@ -1191,6 +1587,17 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf, } +/* Return true if BPT is either a software breakpoint or a hardware + breakpoint. */ + +int +is_breakpoint (const struct breakpoint *bpt) +{ + return (bpt->type == bp_breakpoint + || bpt->type == bp_hardware_breakpoint + || bpt->type == bp_dprintf); +} + /* Return true if BPT is of any hardware watchpoint kind. */ static int @@ -1223,9 +1630,10 @@ is_watchpoint (const struct breakpoint *bpt) static int watchpoint_in_thread_scope (struct watchpoint *b) { - return (ptid_equal (b->watchpoint_thread, null_ptid) - || (ptid_equal (inferior_ptid, b->watchpoint_thread) - && !is_executing (inferior_ptid))); + return (b->base.pspace == current_program_space + && (ptid_equal (b->watchpoint_thread, null_ptid) + || (ptid_equal (inferior_ptid, b->watchpoint_thread) + && !is_executing (inferior_ptid)))); } /* Set watchpoint B to disp_del_at_next_stop, even including its possible @@ -1353,7 +1761,7 @@ update_watchpoint (struct watchpoint *b, int reparse) if (within_current_scope && reparse) { - char *s; + const char *s; if (b->exp) { @@ -1361,7 +1769,7 @@ update_watchpoint (struct watchpoint *b, int reparse) b->exp = NULL; } s = b->exp_string_reparse ? b->exp_string_reparse : b->exp_string; - b->exp = parse_exp_1 (&s, b->exp_valid_block, 0); + b->exp = parse_exp_1 (&s, 0, b->exp_valid_block, 0); /* If the meaning of expression itself changed, the old value is no longer relevant. We don't want to report a watchpoint hit to the user when the old value and the new value may actually @@ -1382,7 +1790,7 @@ update_watchpoint (struct watchpoint *b, int reparse) } s = b->base.cond_string; - b->cond_exp = parse_exp_1 (&s, b->cond_exp_valid_block, 0); + b->cond_exp = parse_exp_1 (&s, 0, b->cond_exp_valid_block, 0); } } @@ -1440,11 +1848,10 @@ update_watchpoint (struct watchpoint *b, int reparse) && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) { CORE_ADDR addr; - int len, type; + int type; struct bp_location *loc, **tmp; addr = value_address (v); - len = TYPE_LENGTH (value_type (v)); type = hw_write; if (b->base.type == bp_read_watchpoint) type = hw_read; @@ -1459,7 +1866,7 @@ update_watchpoint (struct watchpoint *b, int reparse) loc->pspace = frame_pspace; loc->address = addr; - loc->length = len; + loc->length = TYPE_LENGTH (value_type (v)); loc->watchpoint_type = type; } } @@ -1632,99 +2039,456 @@ unduplicated_should_be_inserted (struct bp_location *bl) return result; } -/* Insert a low-level "breakpoint" of some type. BL is the breakpoint - location. Any error messages are printed to TMP_ERROR_STREAM; and - DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems. - Returns 0 for success, 1 if the bp_location type is not supported or - -1 for failure. +/* Parses a conditional described by an expression COND into an + agent expression bytecode suitable for evaluation + by the bytecode interpreter. Return NULL if there was + any error during parsing. */ - NOTE drow/2003-09-09: This routine could be broken down to an - object-style method for each breakpoint or catchpoint type. */ -static int -insert_bp_location (struct bp_location *bl, - struct ui_file *tmp_error_stream, - int *disabled_breaks, - int *hw_breakpoint_error) +static struct agent_expr * +parse_cond_to_aexpr (CORE_ADDR scope, struct expression *cond) { - int val = 0; + struct agent_expr *aexpr = NULL; + struct cleanup *old_chain = NULL; + volatile struct gdb_exception ex; - if (!should_be_inserted (bl) || bl->inserted) - return 0; + if (!cond) + return NULL; - /* Initialize the target-specific information. */ - memset (&bl->target_info, 0, sizeof (bl->target_info)); - bl->target_info.placed_address = bl->address; - bl->target_info.placed_address_space = bl->pspace->aspace; - bl->target_info.length = bl->length; + /* We don't want to stop processing, so catch any errors + that may show up. */ + TRY_CATCH (ex, RETURN_MASK_ERROR) + { + aexpr = gen_eval_for_expr (scope, cond); + } - if (bl->loc_type == bp_loc_software_breakpoint - || bl->loc_type == bp_loc_hardware_breakpoint) + if (ex.reason < 0) { - if (bl->owner->type != bp_hardware_breakpoint) - { - /* If the explicitly specified breakpoint type - is not hardware breakpoint, check the memory map to see - if the breakpoint address is in read only memory or not. + /* If we got here, it means the condition could not be parsed to a valid + bytecode expression and thus can't be evaluated on the target's side. + It's no use iterating through the conditions. */ + return NULL; + } - Two important cases are: - - location type is not hardware breakpoint, memory - is readonly. We change the type of the location to - hardware breakpoint. - - location type is hardware breakpoint, memory is - read-write. This means we've previously made the - location hardware one, but then the memory map changed, - so we undo. - - When breakpoints are removed, remove_breakpoints will use - location types we've just set here, the only possible - problem is that memory map has changed during running - program, but it's not going to work anyway with current - gdb. */ - struct mem_region *mr - = lookup_mem_region (bl->target_info.placed_address); - - if (mr) + /* We have a valid agent expression. */ + return aexpr; +} + +/* Based on location BL, create a list of breakpoint conditions to be + passed on to the target. If we have duplicated locations with different + conditions, we will add such conditions to the list. The idea is that the + target will evaluate the list of conditions and will only notify GDB when + one of them is true. */ + +static void +build_target_condition_list (struct bp_location *bl) +{ + struct bp_location **locp = NULL, **loc2p; + int null_condition_or_parse_error = 0; + int modified = bl->needs_update; + struct bp_location *loc; + + /* This is only meaningful if the target is + evaluating conditions and if the user has + opted for condition evaluation on the target's + side. */ + if (gdb_evaluates_breakpoint_condition_p () + || !target_supports_evaluation_of_breakpoint_conditions ()) + return; + + /* Do a first pass to check for locations with no assigned + conditions or conditions that fail to parse to a valid agent expression + bytecode. If any of these happen, then it's no use to send conditions + to the target since this location will always trigger and generate a + response back to GDB. */ + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) + { + loc = (*loc2p); + if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num) + { + if (modified) { - if (automatic_hardware_breakpoints) - { - enum bp_loc_type new_type; - - if (mr->attrib.mode != MEM_RW) - new_type = bp_loc_hardware_breakpoint; - else - new_type = bp_loc_software_breakpoint; - - if (new_type != bl->loc_type) - { - static int said = 0; + struct agent_expr *aexpr; + + /* Re-parse the conditions since something changed. In that + case we already freed the condition bytecodes (see + force_breakpoint_reinsertion). We just + need to parse the condition to bytecodes again. */ + aexpr = parse_cond_to_aexpr (bl->address, loc->cond); + loc->cond_bytecode = aexpr; + + /* Check if we managed to parse the conditional expression + correctly. If not, we will not send this condition + to the target. */ + if (aexpr) + continue; + } - bl->loc_type = new_type; - if (!said) - { - fprintf_filtered (gdb_stdout, - _("Note: automatically using " - "hardware breakpoints for " - "read-only addresses.\n")); - said = 1; - } - } - } - else if (bl->loc_type == bp_loc_software_breakpoint - && mr->attrib.mode != MEM_RW) - warning (_("cannot set software breakpoint " - "at readonly address %s"), - paddress (bl->gdbarch, bl->address)); + /* If we have a NULL bytecode expression, it means something + went wrong or we have a null condition expression. */ + if (!loc->cond_bytecode) + { + null_condition_or_parse_error = 1; + break; } } - + } + + /* If any of these happened, it means we will have to evaluate the conditions + for the location's address on gdb's side. It is no use keeping bytecodes + for all the other duplicate locations, thus we free all of them here. + + This is so we have a finer control over which locations' conditions are + being evaluated by GDB or the remote stub. */ + if (null_condition_or_parse_error) + { + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) + { + loc = (*loc2p); + if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num) + { + /* Only go as far as the first NULL bytecode is + located. */ + if (!loc->cond_bytecode) + return; + + free_agent_expr (loc->cond_bytecode); + loc->cond_bytecode = NULL; + } + } + } + + /* No NULL conditions or failed bytecode generation. Build a condition list + for this location's address. */ + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) + { + loc = (*loc2p); + if (loc->cond + && is_breakpoint (loc->owner) + && loc->pspace->num == bl->pspace->num + && loc->owner->enable_state == bp_enabled + && loc->enabled) + /* Add the condition to the vector. This will be used later to send the + conditions to the target. */ + VEC_safe_push (agent_expr_p, bl->target_info.conditions, + loc->cond_bytecode); + } + + return; +} + +/* Parses a command described by string CMD into an agent expression + bytecode suitable for evaluation by the bytecode interpreter. + Return NULL if there was any error during parsing. */ + +static struct agent_expr * +parse_cmd_to_aexpr (CORE_ADDR scope, char *cmd) +{ + struct cleanup *old_cleanups = 0; + struct expression *expr, **argvec; + struct agent_expr *aexpr = NULL; + struct cleanup *old_chain = NULL; + volatile struct gdb_exception ex; + const char *cmdrest; + const char *format_start, *format_end; + struct format_piece *fpieces; + int nargs; + struct gdbarch *gdbarch = get_current_arch (); + + if (!cmd) + return NULL; + + cmdrest = cmd; + + if (*cmdrest == ',') + ++cmdrest; + cmdrest = skip_spaces_const (cmdrest); + + if (*cmdrest++ != '"') + error (_("No format string following the location")); + + format_start = cmdrest; + + fpieces = parse_format_string (&cmdrest); + + old_cleanups = make_cleanup (free_format_pieces_cleanup, &fpieces); + + format_end = cmdrest; + + if (*cmdrest++ != '"') + error (_("Bad format string, non-terminated '\"'.")); + + cmdrest = skip_spaces_const (cmdrest); + + if (!(*cmdrest == ',' || *cmdrest == '\0')) + error (_("Invalid argument syntax")); + + if (*cmdrest == ',') + cmdrest++; + cmdrest = skip_spaces_const (cmdrest); + + /* For each argument, make an expression. */ + + argvec = (struct expression **) alloca (strlen (cmd) + * sizeof (struct expression *)); + + nargs = 0; + while (*cmdrest != '\0') + { + const char *cmd1; + + cmd1 = cmdrest; + expr = parse_exp_1 (&cmd1, scope, block_for_pc (scope), 1); + argvec[nargs++] = expr; + cmdrest = cmd1; + if (*cmdrest == ',') + ++cmdrest; + } + + /* We don't want to stop processing, so catch any errors + that may show up. */ + TRY_CATCH (ex, RETURN_MASK_ERROR) + { + aexpr = gen_printf (scope, gdbarch, 0, 0, + format_start, format_end - format_start, + fpieces, nargs, argvec); + } + + if (ex.reason < 0) + { + /* If we got here, it means the command could not be parsed to a valid + bytecode expression and thus can't be evaluated on the target's side. + It's no use iterating through the other commands. */ + return NULL; + } + + do_cleanups (old_cleanups); + + /* We have a valid agent expression, return it. */ + return aexpr; +} + +/* Based on location BL, create a list of breakpoint commands to be + passed on to the target. If we have duplicated locations with + different commands, we will add any such to the list. */ + +static void +build_target_command_list (struct bp_location *bl) +{ + struct bp_location **locp = NULL, **loc2p; + int null_command_or_parse_error = 0; + int modified = bl->needs_update; + struct bp_location *loc; + + /* For now, limit to agent-style dprintf breakpoints. */ + if (bl->owner->type != bp_dprintf + || strcmp (dprintf_style, dprintf_style_agent) != 0) + return; + + if (!target_can_run_breakpoint_commands ()) + return; + + /* Do a first pass to check for locations with no assigned + conditions or conditions that fail to parse to a valid agent expression + bytecode. If any of these happen, then it's no use to send conditions + to the target since this location will always trigger and generate a + response back to GDB. */ + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) + { + loc = (*loc2p); + if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num) + { + if (modified) + { + struct agent_expr *aexpr; + + /* Re-parse the commands since something changed. In that + case we already freed the command bytecodes (see + force_breakpoint_reinsertion). We just + need to parse the command to bytecodes again. */ + aexpr = parse_cmd_to_aexpr (bl->address, + loc->owner->extra_string); + loc->cmd_bytecode = aexpr; + + if (!aexpr) + continue; + } + + /* If we have a NULL bytecode expression, it means something + went wrong or we have a null command expression. */ + if (!loc->cmd_bytecode) + { + null_command_or_parse_error = 1; + break; + } + } + } + + /* If anything failed, then we're not doing target-side commands, + and so clean up. */ + if (null_command_or_parse_error) + { + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) + { + loc = (*loc2p); + if (is_breakpoint (loc->owner) + && loc->pspace->num == bl->pspace->num) + { + /* Only go as far as the first NULL bytecode is + located. */ + if (loc->cmd_bytecode == NULL) + return; + + free_agent_expr (loc->cmd_bytecode); + loc->cmd_bytecode = NULL; + } + } + } + + /* No NULL commands or failed bytecode generation. Build a command list + for this location's address. */ + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) + { + loc = (*loc2p); + if (loc->owner->extra_string + && is_breakpoint (loc->owner) + && loc->pspace->num == bl->pspace->num + && loc->owner->enable_state == bp_enabled + && loc->enabled) + /* Add the command to the vector. This will be used later + to send the commands to the target. */ + VEC_safe_push (agent_expr_p, bl->target_info.tcommands, + loc->cmd_bytecode); + } + + bl->target_info.persist = 0; + /* Maybe flag this location as persistent. */ + if (bl->owner->type == bp_dprintf && disconnected_dprintf) + bl->target_info.persist = 1; +} + +/* Insert a low-level "breakpoint" of some type. BL is the breakpoint + location. Any error messages are printed to TMP_ERROR_STREAM; and + DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems. + Returns 0 for success, 1 if the bp_location type is not supported or + -1 for failure. + + NOTE drow/2003-09-09: This routine could be broken down to an + object-style method for each breakpoint or catchpoint type. */ +static int +insert_bp_location (struct bp_location *bl, + struct ui_file *tmp_error_stream, + int *disabled_breaks, + int *hw_breakpoint_error, + int *hw_bp_error_explained_already) +{ + int val = 0; + char *hw_bp_err_string = NULL; + struct gdb_exception e; + + if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update)) + return 0; + + /* Note we don't initialize bl->target_info, as that wipes out + the breakpoint location's shadow_contents if the breakpoint + is still inserted at that location. This in turn breaks + target_read_memory which depends on these buffers when + a memory read is requested at the breakpoint location: + Once the target_info has been wiped, we fail to see that + we have a breakpoint inserted at that address and thus + read the breakpoint instead of returning the data saved in + the breakpoint location's shadow contents. */ + bl->target_info.placed_address = bl->address; + bl->target_info.placed_address_space = bl->pspace->aspace; + bl->target_info.length = bl->length; + + /* When working with target-side conditions, we must pass all the conditions + for the same breakpoint address down to the target since GDB will not + insert those locations. With a list of breakpoint conditions, the target + can decide when to stop and notify GDB. */ + + if (is_breakpoint (bl->owner)) + { + build_target_condition_list (bl); + build_target_command_list (bl); + /* Reset the modification marker. */ + bl->needs_update = 0; + } + + if (bl->loc_type == bp_loc_software_breakpoint + || bl->loc_type == bp_loc_hardware_breakpoint) + { + if (bl->owner->type != bp_hardware_breakpoint) + { + /* If the explicitly specified breakpoint type + is not hardware breakpoint, check the memory map to see + if the breakpoint address is in read only memory or not. + + Two important cases are: + - location type is not hardware breakpoint, memory + is readonly. We change the type of the location to + hardware breakpoint. + - location type is hardware breakpoint, memory is + read-write. This means we've previously made the + location hardware one, but then the memory map changed, + so we undo. + + When breakpoints are removed, remove_breakpoints will use + location types we've just set here, the only possible + problem is that memory map has changed during running + program, but it's not going to work anyway with current + gdb. */ + struct mem_region *mr + = lookup_mem_region (bl->target_info.placed_address); + + if (mr) + { + if (automatic_hardware_breakpoints) + { + enum bp_loc_type new_type; + + if (mr->attrib.mode != MEM_RW) + new_type = bp_loc_hardware_breakpoint; + else + new_type = bp_loc_software_breakpoint; + + if (new_type != bl->loc_type) + { + static int said = 0; + + bl->loc_type = new_type; + if (!said) + { + fprintf_filtered (gdb_stdout, + _("Note: automatically using " + "hardware breakpoints for " + "read-only addresses.\n")); + said = 1; + } + } + } + else if (bl->loc_type == bp_loc_software_breakpoint + && mr->attrib.mode != MEM_RW) + warning (_("cannot set software breakpoint " + "at readonly address %s"), + paddress (bl->gdbarch, bl->address)); + } + } + /* First check to see if we have to handle an overlay. */ if (overlay_debugging == ovly_off || bl->section == NULL || !(section_is_overlay (bl->section))) { /* No overlay handling: just set the breakpoint. */ - - val = bl->owner->ops->insert_location (bl); + TRY_CATCH (e, RETURN_MASK_ALL) + { + val = bl->owner->ops->insert_location (bl); + } + if (e.reason < 0) + { + val = 1; + hw_bp_err_string = (char *) e.message; + } } else { @@ -1758,7 +2522,15 @@ insert_bp_location (struct bp_location *bl, if (section_is_mapped (bl->section)) { /* Yes. This overlay section is mapped into memory. */ - val = bl->owner->ops->insert_location (bl); + TRY_CATCH (e, RETURN_MASK_ALL) + { + val = bl->owner->ops->insert_location (bl); + } + if (e.reason < 0) + { + val = 1; + hw_bp_err_string = (char *) e.message; + } } else { @@ -1794,11 +2566,13 @@ insert_bp_location (struct bp_location *bl, { if (bl->loc_type == bp_loc_hardware_breakpoint) { - *hw_breakpoint_error = 1; - fprintf_unfiltered (tmp_error_stream, - "Cannot insert hardware " - "breakpoint %d.\n", - bl->owner->number); + *hw_breakpoint_error = 1; + *hw_bp_error_explained_already = hw_bp_err_string != NULL; + fprintf_unfiltered (tmp_error_stream, + "Cannot insert hardware breakpoint %d%s", + bl->owner->number, hw_bp_err_string ? ":" : ".\n"); + if (hw_bp_err_string) + fprintf_unfiltered (tmp_error_stream, "%s.\n", hw_bp_err_string); } else { @@ -1965,6 +2739,80 @@ insert_breakpoints (void) insert_breakpoint_locations (); } +/* Invoke CALLBACK for each of bp_location. */ + +void +iterate_over_bp_locations (walk_bp_location_callback callback) +{ + struct bp_location *loc, **loc_tmp; + + ALL_BP_LOCATIONS (loc, loc_tmp) + { + callback (loc, NULL); + } +} + +/* This is used when we need to synch breakpoint conditions between GDB and the + target. It is the case with deleting and disabling of breakpoints when using + always-inserted mode. */ + +static void +update_inserted_breakpoint_locations (void) +{ + struct bp_location *bl, **blp_tmp; + int error_flag = 0; + int val = 0; + int disabled_breaks = 0; + int hw_breakpoint_error = 0; + int hw_bp_details_reported = 0; + + struct ui_file *tmp_error_stream = mem_fileopen (); + struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream); + + /* Explicitly mark the warning -- this will only be printed if + there was an error. */ + fprintf_unfiltered (tmp_error_stream, "Warning:\n"); + + save_current_space_and_thread (); + + ALL_BP_LOCATIONS (bl, blp_tmp) + { + /* We only want to update software breakpoints and hardware + breakpoints. */ + if (!is_breakpoint (bl->owner)) + continue; + + /* We only want to update locations that are already inserted + and need updating. This is to avoid unwanted insertion during + deletion of breakpoints. */ + if (!bl->inserted || (bl->inserted && !bl->needs_update)) + continue; + + switch_to_program_space_and_thread (bl->pspace); + + /* For targets that support global breakpoints, there's no need + to select an inferior to insert breakpoint to. In fact, even + if we aren't attached to any process yet, we should still + insert breakpoints. */ + if (!gdbarch_has_global_breakpoints (target_gdbarch ()) + && ptid_equal (inferior_ptid, null_ptid)) + continue; + + val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks, + &hw_breakpoint_error, &hw_bp_details_reported); + if (val) + error_flag = val; + } + + if (error_flag) + { + target_terminal_ours_for_output (); + error_stream (tmp_error_stream); + } + + do_cleanups (cleanups); +} + /* Used when starting or continuing the program. */ static void @@ -1976,6 +2824,7 @@ insert_breakpoint_locations (void) int val = 0; int disabled_breaks = 0; int hw_breakpoint_error = 0; + int hw_bp_error_explained_already = 0; struct ui_file *tmp_error_stream = mem_fileopen (); struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream); @@ -1988,7 +2837,7 @@ insert_breakpoint_locations (void) ALL_BP_LOCATIONS (bl, blp_tmp) { - if (!should_be_inserted (bl) || bl->inserted) + if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update)) continue; /* There is no point inserting thread-specific breakpoints if @@ -2004,12 +2853,12 @@ insert_breakpoint_locations (void) to select an inferior to insert breakpoint to. In fact, even if we aren't attached to any process yet, we should still insert breakpoints. */ - if (!gdbarch_has_global_breakpoints (target_gdbarch) + if (!gdbarch_has_global_breakpoints (target_gdbarch ()) && ptid_equal (inferior_ptid, null_ptid)) continue; val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks, - &hw_breakpoint_error); + &hw_breakpoint_error, &hw_bp_error_explained_already); if (val) error_flag = val; } @@ -2054,7 +2903,7 @@ insert_breakpoint_locations (void) { /* If a hardware breakpoint or watchpoint was inserted, add a message about possibly exhausted resources. */ - if (hw_breakpoint_error) + if (hw_breakpoint_error && !hw_bp_error_explained_already) { fprintf_unfiltered (tmp_error_stream, "Could not insert hardware breakpoints:\n\ @@ -2099,6 +2948,9 @@ remove_breakpoints_pid (int pid) if (bl->pspace != inf->pspace) continue; + if (bl->owner->type == bp_dprintf) + continue; + if (bl->inserted) { val = remove_breakpoint (bl, mark_uninserted); @@ -2116,7 +2968,7 @@ reattach_breakpoints (int pid) struct bp_location *bl, **blp_tmp; int val; struct ui_file *tmp_error_stream; - int dummy1 = 0, dummy2 = 0; + int dummy1 = 0, dummy2 = 0, dummy3 = 0; struct inferior *inf; struct thread_info *tp; @@ -2140,7 +2992,7 @@ reattach_breakpoints (int pid) if (bl->inserted) { bl->inserted = 0; - val = insert_bp_location (bl, tmp_error_stream, &dummy1, &dummy2); + val = insert_bp_location (bl, tmp_error_stream, &dummy1, &dummy2, &dummy3); if (val != 0) { do_cleanups (old_chain); @@ -2208,11 +3060,23 @@ struct breakpoint_objfile_data /* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */ struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES]; + /* True if we have looked for longjmp probes. */ + int longjmp_searched; + + /* SystemTap probe points for longjmp (if any). */ + VEC (probe_p) *longjmp_probes; + /* Minimal symbol for "std::terminate()" (if any). */ struct minimal_symbol *terminate_msym; /* Minimal symbol for "_Unwind_DebugHook" (if any). */ struct minimal_symbol *exception_msym; + + /* True if we have looked for exception probes. */ + int exception_searched; + + /* SystemTap probe points for unwinding (if any). */ + VEC (probe_p) *exception_probes; }; static const struct objfile_data *breakpoint_objfile_key; @@ -2248,6 +3112,15 @@ get_breakpoint_objfile_data (struct objfile *objfile) return bp_objfile_data; } +static void +free_breakpoint_probes (struct objfile *obj, void *data) +{ + struct breakpoint_objfile_data *bp_objfile_data = data; + + VEC_free (probe_p, bp_objfile_data->longjmp_probes); + VEC_free (probe_p, bp_objfile_data->exception_probes); +} + static void create_overlay_event_breakpoint (void) { @@ -2325,16 +3198,47 @@ create_longjmp_master_breakpoint (void) bp_objfile_data = get_breakpoint_objfile_data (objfile); - for (i = 0; i < NUM_LONGJMP_NAMES; i++) + if (!bp_objfile_data->longjmp_searched) { - struct breakpoint *b; - const char *func_name; - CORE_ADDR addr; + bp_objfile_data->longjmp_probes + = find_probes_in_objfile (objfile, "libc", "longjmp"); + bp_objfile_data->longjmp_searched = 1; + } - if (msym_not_found_p (bp_objfile_data->longjmp_msym[i])) - continue; + if (bp_objfile_data->longjmp_probes != NULL) + { + int i; + struct probe *probe; + struct gdbarch *gdbarch = get_objfile_arch (objfile); + + for (i = 0; + VEC_iterate (probe_p, + bp_objfile_data->longjmp_probes, + i, probe); + ++i) + { + struct breakpoint *b; - func_name = longjmp_names[i]; + b = create_internal_breakpoint (gdbarch, probe->address, + bp_longjmp_master, + &internal_breakpoint_ops); + b->addr_string = xstrdup ("-probe-stap libc:longjmp"); + b->enable_state = bp_disabled; + } + + continue; + } + + for (i = 0; i < NUM_LONGJMP_NAMES; i++) + { + struct breakpoint *b; + const char *func_name; + CORE_ADDR addr; + + if (msym_not_found_p (bp_objfile_data->longjmp_msym[i])) + continue; + + func_name = longjmp_names[i]; if (bp_objfile_data->longjmp_msym[i] == NULL) { struct minimal_symbol *m; @@ -2420,7 +3324,7 @@ create_std_terminate_master_breakpoint (void) /* Install a master breakpoint on the unwinder's debug hook. */ -void +static void create_exception_master_breakpoint (void) { struct objfile *objfile; @@ -2435,6 +3339,40 @@ create_exception_master_breakpoint (void) bp_objfile_data = get_breakpoint_objfile_data (objfile); + /* We prefer the SystemTap probe point if it exists. */ + if (!bp_objfile_data->exception_searched) + { + bp_objfile_data->exception_probes + = find_probes_in_objfile (objfile, "libgcc", "unwind"); + bp_objfile_data->exception_searched = 1; + } + + if (bp_objfile_data->exception_probes != NULL) + { + struct gdbarch *gdbarch = get_objfile_arch (objfile); + int i; + struct probe *probe; + + for (i = 0; + VEC_iterate (probe_p, + bp_objfile_data->exception_probes, + i, probe); + ++i) + { + struct breakpoint *b; + + b = create_internal_breakpoint (gdbarch, probe->address, + bp_exception_master, + &internal_breakpoint_ops); + b->addr_string = xstrdup ("-probe-stap libgcc:unwind"); + b->enable_state = bp_disabled; + } + + continue; + } + + /* Otherwise, try the hook function. */ + if (msym_not_found_p (bp_objfile_data->exception_msym)) continue; @@ -2523,6 +3461,7 @@ update_breakpoints_after_exec (void) /* Longjmp and longjmp-resume breakpoints are also meaningless after an exec. */ if (b->type == bp_longjmp || b->type == bp_longjmp_resume + || b->type == bp_longjmp_call_dummy || b->type == bp_exception || b->type == bp_exception_resume) { delete_breakpoint (b); @@ -2586,18 +3525,18 @@ update_breakpoints_after_exec (void) } int -detach_breakpoints (int pid) +detach_breakpoints (ptid_t ptid) { struct bp_location *bl, **blp_tmp; int val = 0; struct cleanup *old_chain = save_inferior_ptid (); struct inferior *inf = current_inferior (); - if (pid == PIDGET (inferior_ptid)) + if (PIDGET (ptid) == PIDGET (inferior_ptid)) error (_("Cannot detach breakpoints of inferior_ptid")); /* Set inferior_ptid; remove_breakpoint_1 uses this global. */ - inferior_ptid = pid_to_ptid (pid); + inferior_ptid = ptid; ALL_BP_LOCATIONS (bl, blp_tmp) { if (bl->pspace != inf->pspace) @@ -2795,7 +3734,7 @@ breakpoint_init_inferior (enum inf_context context) /* If breakpoint locations are shared across processes, then there's nothing to do. */ - if (gdbarch_has_global_breakpoints (target_gdbarch)) + if (gdbarch_has_global_breakpoints (target_gdbarch ())) return; ALL_BP_LOCATIONS (bl, blp_tmp) @@ -2814,6 +3753,7 @@ breakpoint_init_inferior (enum inf_context context) switch (b->type) { case bp_call_dummy: + case bp_longjmp_call_dummy: /* If the call dummy breakpoint is at the entry point it will cause problems when the inferior is rerun, so we better get @@ -2839,6 +3779,10 @@ breakpoint_init_inferior (enum inf_context context) (gdb) tar rem :9999 # remote Windows gdbserver. */ + case bp_step_resume: + + /* Also remove step-resume breakpoints. */ + delete_breakpoint (b); break; @@ -3111,7 +4055,7 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc, in breakpoint.h. */ int -ep_is_catchpoint (struct breakpoint *ep) +is_catchpoint (struct breakpoint *ep) { return (ep->type == bp_catchpoint); } @@ -3202,6 +4146,39 @@ bpstat_find_breakpoint (bpstat bsp, struct breakpoint *breakpoint) return NULL; } +/* See breakpoint.h. */ + +enum bpstat_signal_value +bpstat_explains_signal (bpstat bsp, enum gdb_signal sig) +{ + enum bpstat_signal_value result = BPSTAT_SIGNAL_NO; + + for (; bsp != NULL; bsp = bsp->next) + { + /* Ensure that, if we ever entered this loop, then we at least + return BPSTAT_SIGNAL_HIDE. */ + enum bpstat_signal_value newval; + + if (bsp->breakpoint_at == NULL) + { + /* A moribund location can never explain a signal other than + GDB_SIGNAL_TRAP. */ + if (sig == GDB_SIGNAL_TRAP) + newval = BPSTAT_SIGNAL_HIDE; + else + newval = BPSTAT_SIGNAL_NO; + } + else + newval = bsp->breakpoint_at->ops->explains_signal (bsp->breakpoint_at, + sig); + + if (newval > result) + result = newval; + } + + return result; +} + /* Put in *NUM the breakpoint number of the first breakpoint we are stopped at. *BSP upon return is a bpstat which points to the remaining breakpoints stopped at (but which is not guaranteed to be @@ -3473,6 +4450,78 @@ print_bp_stop_message (bpstat bs) } } +/* A helper function that prints a shared library stopped event. */ + +static void +print_solib_event (int is_catchpoint) +{ + int any_deleted + = !VEC_empty (char_ptr, current_program_space->deleted_solibs); + int any_added + = !VEC_empty (so_list_ptr, current_program_space->added_solibs); + + if (!is_catchpoint) + { + if (any_added || any_deleted) + ui_out_text (current_uiout, + _("Stopped due to shared library event:\n")); + else + ui_out_text (current_uiout, + _("Stopped due to shared library event (no " + "libraries added or removed)\n")); + } + + if (ui_out_is_mi_like_p (current_uiout)) + ui_out_field_string (current_uiout, "reason", + async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT)); + + if (any_deleted) + { + struct cleanup *cleanup; + char *name; + int ix; + + ui_out_text (current_uiout, _(" Inferior unloaded ")); + cleanup = make_cleanup_ui_out_list_begin_end (current_uiout, + "removed"); + for (ix = 0; + VEC_iterate (char_ptr, current_program_space->deleted_solibs, + ix, name); + ++ix) + { + if (ix > 0) + ui_out_text (current_uiout, " "); + ui_out_field_string (current_uiout, "library", name); + ui_out_text (current_uiout, "\n"); + } + + do_cleanups (cleanup); + } + + if (any_added) + { + struct so_list *iter; + int ix; + struct cleanup *cleanup; + + ui_out_text (current_uiout, _(" Inferior loaded ")); + cleanup = make_cleanup_ui_out_list_begin_end (current_uiout, + "added"); + for (ix = 0; + VEC_iterate (so_list_ptr, current_program_space->added_solibs, + ix, iter); + ++ix) + { + if (ix > 0) + ui_out_text (current_uiout, " "); + ui_out_field_string (current_uiout, "library", iter->so_name); + ui_out_text (current_uiout, "\n"); + } + + do_cleanups (cleanup); + } +} + /* Print a message indicating what happened. This is called from normal_stop(). The input to this routine is the head of the bpstat list - a list of the eventpoints that caused this stop. KIND is @@ -3517,10 +4566,7 @@ bpstat_print (bpstat bs, int kind) OS-level shared library event, do the same thing. */ if (kind == TARGET_WAITKIND_LOADED) { - ui_out_text (current_uiout, _("Stopped due to shared library event\n")); - if (ui_out_is_mi_like_p (current_uiout)) - ui_out_field_string (current_uiout, "reason", - async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT)); + print_solib_event (0); return PRINT_NOTHING; } @@ -3808,14 +4854,15 @@ which its expression is valid.\n"); static int bpstat_check_location (const struct bp_location *bl, - struct address_space *aspace, CORE_ADDR bp_addr) + struct address_space *aspace, CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { struct breakpoint *b = bl->owner; /* BL is from an existing breakpoint. */ gdb_assert (b != NULL); - return b->ops->breakpoint_hit (bl, aspace, bp_addr); + return b->ops->breakpoint_hit (bl, aspace, bp_addr, ws); } /* Determine if the watched values have actually changed, and we @@ -3996,6 +5043,10 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid) b = bs->breakpoint_at; gdb_assert (b != NULL); + /* Even if the target evaluated the condition on its end and notified GDB, we + need to do so again since GDB does not know if we stopped due to a + breakpoint or a single step breakpoint. */ + if (frame_id_p (b->frame_id) && !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ()))) bs->stop = 0; @@ -4095,7 +5146,6 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid) else if (b->ignore_count > 0) { b->ignore_count--; - annotate_ignore_count_change (); bs->stop = 0; /* Increase the hit count even though we don't stop. */ ++(b->hit_count); @@ -4125,7 +5175,8 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid) bpstat bpstat_stop_status (struct address_space *aspace, - CORE_ADDR bp_addr, ptid_t ptid) + CORE_ADDR bp_addr, ptid_t ptid, + const struct target_waitstatus *ws) { struct breakpoint *b = NULL; struct bp_location *bl; @@ -4160,10 +5211,10 @@ bpstat_stop_status (struct address_space *aspace, if (b->type == bp_hardware_watchpoint && bl != b->loc) break; - if (bl->shlib_disabled) + if (!bl->enabled || bl->shlib_disabled) continue; - if (!bpstat_check_location (bl, aspace, bp_addr)) + if (!bpstat_check_location (bl, aspace, bp_addr, ws)) continue; /* Come here if it's a watchpoint, or if the break address @@ -4203,6 +5254,19 @@ bpstat_stop_status (struct address_space *aspace, } } + /* A bit of special processing for shlib breakpoints. We need to + process solib loading here, so that the lists of loaded and + unloaded libraries are correct before we handle "catch load" and + "catch unload". */ + for (bs = bs_head; bs != NULL; bs = bs->next) + { + if (bs->breakpoint_at && bs->breakpoint_at->type == bp_shlib_event) + { + handle_solib_event (); + break; + } + } + /* Now go through the locations that caused the target to stop, and check whether we're interested in reporting this stop to higher layers, or whether we should resume the target transparently. */ @@ -4228,7 +5292,9 @@ bpstat_stop_status (struct address_space *aspace, /* We will stop here. */ if (b->disposition == disp_disable) { - if (b->enable_state != bp_permanent) + --(b->enable_count); + if (b->enable_count <= 0 + && b->enable_state != bp_permanent) b->enable_state = bp_disabled; removed_any = 1; } @@ -4239,12 +5305,16 @@ bpstat_stop_status (struct address_space *aspace, if (command_line_is_silent (bs->commands ? bs->commands->commands : NULL)) bs->print = 0; + + b->ops->after_condition_true (bs); } - /* Print nothing for this entry if we don't stop or don't print. */ - if (bs->stop == 0 || bs->print == 0) - bs->print_it = print_it_noop; } + + /* Print nothing for this entry if we don't stop or don't + print. */ + if (!bs->stop || !bs->print) + bs->print_it = print_it_noop; } /* If we aren't stopping, the value of some hardware watchpoint may @@ -4290,6 +5360,25 @@ handle_jit_event (void) target_terminal_inferior (); } +/* Handle an solib event by calling solib_add. */ + +void +handle_solib_event (void) +{ + clear_program_space_solib_cache (current_inferior ()->pspace); + + /* Check for any newly added shared libraries if we're supposed to + be adding them automatically. Switch terminal for any messages + produced by breakpoint_re_set. */ + target_terminal_ours_for_output (); +#ifdef SOLIB_ADD + SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); +#else + solib_add (NULL, 0, ¤t_target, auto_solib_add); +#endif + target_terminal_inferior (); +} + /* Prepare WHAT final decision for infrun. */ /* Decide what infrun needs to do with this bpstat. */ @@ -4298,10 +5387,6 @@ struct bpstat_what bpstat_what (bpstat bs_head) { struct bpstat_what retval; - /* We need to defer calling `solib_add', as adding new symbols - resets breakpoints, which in turn deletes breakpoint locations, - and hence may clear unprocessed entries in the BS chain. */ - int shlib_event = 0; int jit_event = 0; bpstat bs; @@ -4333,6 +5418,7 @@ bpstat_what (bpstat bs_head) case bp_hardware_breakpoint: case bp_until: case bp_finish: + case bp_shlib_event: if (bs->stop) { if (bs->print) @@ -4361,9 +5447,10 @@ bpstat_what (bpstat bs_head) } break; case bp_longjmp: + case bp_longjmp_call_dummy: case bp_exception: this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME; - retval.is_longjmp = bptype == bp_longjmp; + retval.is_longjmp = bptype != bp_exception; break; case bp_longjmp_resume: case bp_exception_resume: @@ -4410,18 +5497,6 @@ bpstat_what (bpstat bs_head) This requires no further action. */ } break; - case bp_shlib_event: - shlib_event = 1; - - /* 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 dynamically - loaded objects (among other things). */ - if (stop_on_solib_events) - this_action = BPSTAT_WHAT_STOP_NOISY; - else - this_action = BPSTAT_WHAT_SINGLE; - break; case bp_jit_event: jit_event = 1; this_action = BPSTAT_WHAT_SINGLE; @@ -4456,6 +5531,14 @@ bpstat_what (bpstat bs_head) PC of the former breakpoint. */ this_action = BPSTAT_WHAT_KEEP_CHECKING; break; + + case bp_dprintf: + if (bs->stop) + this_action = BPSTAT_WHAT_STOP_SILENT; + else + this_action = BPSTAT_WHAT_SINGLE; + break; + default: internal_error (__FILE__, __LINE__, _("bpstat_what: unhandled bptype %d"), (int) bptype); @@ -4467,27 +5550,6 @@ bpstat_what (bpstat bs_head) /* These operations may affect the bs->breakpoint_at state so they are delayed after MAIN_ACTION is decided above. */ - if (shlib_event) - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "bpstat_what: bp_shlib_event\n"); - - /* Check for any newly added shared libraries if we're supposed - to be adding them automatically. */ - - /* Switch terminal for any messages produced by - breakpoint_re_set. */ - target_terminal_ours_for_output (); - -#ifdef SOLIB_ADD - SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); -#else - solib_add (NULL, 0, ¤t_target, auto_solib_add); -#endif - - target_terminal_inferior (); - } - if (jit_event) { if (debug_infrun) @@ -4572,6 +5634,66 @@ wrap_indent_at_field (struct ui_out *uiout, const char *col_name) return NULL; } +/* Determine if the locations of this breakpoint will have their conditions + evaluated by the target, host or a mix of both. Returns the following: + + "host": Host evals condition. + "host or target": Host or Target evals condition. + "target": Target evals condition. +*/ + +static const char * +bp_condition_evaluator (struct breakpoint *b) +{ + struct bp_location *bl; + char host_evals = 0; + char target_evals = 0; + + if (!b) + return NULL; + + if (!is_breakpoint (b)) + return NULL; + + if (gdb_evaluates_breakpoint_condition_p () + || !target_supports_evaluation_of_breakpoint_conditions ()) + return condition_evaluation_host; + + for (bl = b->loc; bl; bl = bl->next) + { + if (bl->cond_bytecode) + target_evals++; + else + host_evals++; + } + + if (host_evals && target_evals) + return condition_evaluation_both; + else if (target_evals) + return condition_evaluation_target; + else + return condition_evaluation_host; +} + +/* Determine the breakpoint location's condition evaluator. This is + similar to bp_condition_evaluator, but for locations. */ + +static const char * +bp_location_condition_evaluator (struct bp_location *bl) +{ + if (bl && !is_breakpoint (bl->owner)) + return NULL; + + if (gdb_evaluates_breakpoint_condition_p () + || !target_supports_evaluation_of_breakpoint_conditions ()) + return condition_evaluation_host; + + if (bl && bl->cond_bytecode) + return condition_evaluation_target; + else + return condition_evaluation_host; +} + /* Print the LOC location out of the list of B->LOC locations. */ static void @@ -4589,7 +5711,7 @@ print_breakpoint_location (struct breakpoint *b, if (b->display_canonical) ui_out_field_string (uiout, "what", b->addr_string); - else if (loc && loc->source_file) + else if (loc && loc->symtab) { struct symbol *sym = find_pc_sect_function (loc->address, loc->section); @@ -4602,26 +5724,22 @@ print_breakpoint_location (struct breakpoint *b, ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what")); ui_out_text (uiout, "at "); } - ui_out_field_string (uiout, "file", loc->source_file); + ui_out_field_string (uiout, "file", + symtab_to_filename_for_display (loc->symtab)); ui_out_text (uiout, ":"); - + if (ui_out_is_mi_like_p (uiout)) - { - struct symtab_and_line sal = find_pc_line (loc->address, 0); - char *fullname = symtab_to_fullname (sal.symtab); - - if (fullname) - ui_out_field_string (uiout, "fullname", fullname); - } + ui_out_field_string (uiout, "fullname", + symtab_to_fullname (loc->symtab)); ui_out_field_int (uiout, "line", loc->line_number); } else if (loc) { - struct ui_stream *stb = ui_out_stream_new (uiout); - struct cleanup *stb_chain = make_cleanup_ui_out_stream_delete (stb); + struct ui_file *stb = mem_fileopen (); + struct cleanup *stb_chain = make_cleanup_ui_file_delete (stb); - print_address_symbolic (loc->gdbarch, loc->address, stb->stream, + print_address_symbolic (loc->gdbarch, loc->address, stb, demangle, ""); ui_out_field_stream (uiout, "at", stb); @@ -4630,6 +5748,16 @@ print_breakpoint_location (struct breakpoint *b, else ui_out_field_string (uiout, "pending", b->addr_string); + if (loc && is_breakpoint (b) + && breakpoint_condition_evaluation_mode () == condition_evaluation_target + && bp_condition_evaluator (b) == condition_evaluation_both) + { + ui_out_text (uiout, " ("); + ui_out_field_string (uiout, "evaluated-by", + bp_location_condition_evaluator (loc)); + ui_out_text (uiout, ")"); + } + do_cleanups (old_chain); } @@ -4654,6 +5782,7 @@ bptype_string (enum bptype type) {bp_access_watchpoint, "acc watchpoint"}, {bp_longjmp, "longjmp"}, {bp_longjmp_resume, "longjmp resume"}, + {bp_longjmp_call_dummy, "longjmp for call dummy"}, {bp_exception, "exception"}, {bp_exception_resume, "exception resume"}, {bp_step_resume, "step resume"}, @@ -4671,6 +5800,7 @@ bptype_string (enum bptype type) {bp_tracepoint, "tracepoint"}, {bp_fast_tracepoint, "fast tracepoint"}, {bp_static_tracepoint, "static tracepoint"}, + {bp_dprintf, "dprintf"}, {bp_jit_event, "jit events"}, {bp_gnu_ifunc_resolver, "STT_GNU_IFUNC resolver"}, {bp_gnu_ifunc_resolver_return, "STT_GNU_IFUNC resolver return"}, @@ -4685,6 +5815,51 @@ bptype_string (enum bptype type) return bptypes[(int) type].description; } +DEF_VEC_I(int); + +/* For MI, output a field named 'thread-groups' with a list as the value. + For CLI, prefix the list with the string 'inf'. */ + +static void +output_thread_groups (struct ui_out *uiout, + const char *field_name, + VEC(int) *inf_num, + int mi_only) +{ + struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (uiout, + field_name); + int is_mi = ui_out_is_mi_like_p (uiout); + int inf; + int i; + + /* For backward compatibility, don't display inferiors in CLI unless + there are several. Always display them for MI. */ + if (!is_mi && mi_only) + return; + + for (i = 0; VEC_iterate (int, inf_num, i, inf); ++i) + { + if (is_mi) + { + char mi_group[10]; + + xsnprintf (mi_group, sizeof (mi_group), "i%d", inf); + ui_out_field_string (uiout, NULL, mi_group); + } + else + { + if (i == 0) + ui_out_text (uiout, " inf "); + else + ui_out_text (uiout, ", "); + + ui_out_text (uiout, plongest (inf)); + } + } + + do_cleanups (back_to); +} + /* Print B to gdb_stdout. */ static void @@ -4795,6 +5970,7 @@ print_one_breakpoint_location (struct breakpoint *b, case bp_finish: case bp_longjmp: case bp_longjmp_resume: + case bp_longjmp_call_dummy: case bp_exception: case bp_exception_resume: case bp_step_resume: @@ -4811,6 +5987,7 @@ print_one_breakpoint_location (struct breakpoint *b, case bp_tracepoint: case bp_fast_tracepoint: case bp_static_tracepoint: + case bp_dprintf: case bp_jit_event: case bp_gnu_ifunc_resolver: case bp_gnu_ifunc_resolver_return: @@ -4834,35 +6011,30 @@ print_one_breakpoint_location (struct breakpoint *b, } - /* For backward compatibility, don't display inferiors unless there - are several. */ - if (loc != NULL - && !header_of_multiple - && (allflag - || (!gdbarch_has_global_breakpoints (target_gdbarch) - && (number_of_program_spaces () > 1 - || number_of_inferiors () > 1) - /* LOC is for existing B, it cannot be in - moribund_locations and thus having NULL OWNER. */ - && loc->owner->type != bp_catchpoint))) + if (loc != NULL && !header_of_multiple) { struct inferior *inf; - int first = 1; + VEC(int) *inf_num = NULL; + int mi_only = 1; - for (inf = inferior_list; inf != NULL; inf = inf->next) + ALL_INFERIORS (inf) { if (inf->pspace == loc->pspace) - { - if (first) - { - first = 0; - ui_out_text (uiout, " inf "); - } - else - ui_out_text (uiout, ", "); - ui_out_text (uiout, plongest (inf->num)); - } + VEC_safe_push (int, inf_num, inf->num); } + + /* For backward compatibility, don't display inferiors in CLI unless + there are several. Always display for MI. */ + if (allflag + || (!gdbarch_has_global_breakpoints (target_gdbarch ()) + && (number_of_program_spaces () > 1 + || number_of_inferiors () > 1) + /* LOC is for existing B, it cannot be in + moribund_locations and thus having NULL OWNER. */ + && loc->owner->type != bp_catchpoint)) + mi_only = 0; + output_thread_groups (uiout, "thread-groups", inf_num, mi_only); + VEC_free (int, inf_num); } if (!part_of_multiple) @@ -4905,6 +6077,18 @@ print_one_breakpoint_location (struct breakpoint *b, else ui_out_text (uiout, "\tstop only if "); ui_out_field_string (uiout, "cond", b->cond_string); + + /* Print whether the target is doing the breakpoint's condition + evaluation. If GDB is doing the evaluation, don't print anything. */ + if (is_breakpoint (b) + && breakpoint_condition_evaluation_mode () + == condition_evaluation_target) + { + ui_out_text (uiout, " ("); + ui_out_field_string (uiout, "evaluated-by", + bp_condition_evaluator (b)); + ui_out_text (uiout, " evals)"); + } ui_out_text (uiout, "\n"); } @@ -4916,28 +6100,31 @@ print_one_breakpoint_location (struct breakpoint *b, ui_out_text (uiout, "\n"); } - if (!part_of_multiple && b->hit_count) + if (!part_of_multiple) { - /* FIXME should make an annotation for this. */ - if (ep_is_catchpoint (b)) - ui_out_text (uiout, "\tcatchpoint"); - else if (is_tracepoint (b)) - ui_out_text (uiout, "\ttracepoint"); - else - ui_out_text (uiout, "\tbreakpoint"); - ui_out_text (uiout, " already hit "); - ui_out_field_int (uiout, "times", b->hit_count); - if (b->hit_count == 1) - ui_out_text (uiout, " time\n"); + if (b->hit_count) + { + /* FIXME should make an annotation for this. */ + if (is_catchpoint (b)) + ui_out_text (uiout, "\tcatchpoint"); + else if (is_tracepoint (b)) + ui_out_text (uiout, "\ttracepoint"); + else + ui_out_text (uiout, "\tbreakpoint"); + ui_out_text (uiout, " already hit "); + ui_out_field_int (uiout, "times", b->hit_count); + if (b->hit_count == 1) + ui_out_text (uiout, " time\n"); + else + ui_out_text (uiout, " times\n"); + } else - ui_out_text (uiout, " times\n"); + { + /* Output the count also if it is zero, but only if this is mi. */ + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_int (uiout, "times", b->hit_count); + } } - - /* Output the count also if it is zero, but only if this is mi. - FIXME: Should have a better test for this. */ - if (ui_out_is_mi_like_p (uiout)) - if (!part_of_multiple && b->hit_count == 0) - ui_out_field_int (uiout, "times", b->hit_count); if (!part_of_multiple && b->ignore_count) { @@ -4947,6 +6134,23 @@ print_one_breakpoint_location (struct breakpoint *b, ui_out_text (uiout, " hits\n"); } + /* Note that an enable count of 1 corresponds to "enable once" + behavior, which is reported by the combination of enablement and + disposition, so we don't need to mention it here. */ + if (!part_of_multiple && b->enable_count > 1) + { + annotate_field (8); + ui_out_text (uiout, "\tdisable after "); + /* Tweak the wording to clarify that ignore and enable counts + are distinct, and have additive effect. */ + if (b->ignore_count) + ui_out_text (uiout, "additional "); + else + ui_out_text (uiout, "next "); + ui_out_field_int (uiout, "enable", b->enable_count); + ui_out_text (uiout, " hits\n"); + } + if (!part_of_multiple && is_tracepoint (b)) { struct tracepoint *tp = (struct tracepoint *) b; @@ -4958,7 +6162,7 @@ print_one_breakpoint_location (struct breakpoint *b, ui_out_text (uiout, " bytes\n"); } } - + l = b->commands ? b->commands->commands : NULL; if (!part_of_multiple && l) { @@ -4981,6 +6185,25 @@ print_one_breakpoint_location (struct breakpoint *b, ui_out_field_int (uiout, "pass", t->pass_count); ui_out_text (uiout, " \n"); } + + /* Don't display it when tracepoint or tracepoint location is + pending. */ + if (!header_of_multiple && loc != NULL && !loc->shlib_disabled) + { + annotate_field (11); + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "installed", + loc->inserted ? "y" : "n"); + else + { + if (loc->inserted) + ui_out_text (uiout, "\t"); + else + ui_out_text (uiout, "\tnot "); + ui_out_text (uiout, "installed on target\n"); + } + } } if (ui_out_is_mi_like_p (uiout) && !part_of_multiple) @@ -5461,7 +6684,7 @@ static int breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1, struct address_space *aspace2, CORE_ADDR addr2) { - return ((gdbarch_has_global_breakpoints (target_gdbarch) + return ((gdbarch_has_global_breakpoints (target_gdbarch ()) || aspace1 == aspace2) && addr1 == addr2); } @@ -5476,7 +6699,7 @@ breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1, int len1, struct address_space *aspace2, CORE_ADDR addr2) { - return ((gdbarch_has_global_breakpoints (target_gdbarch) + return ((gdbarch_has_global_breakpoints (target_gdbarch ()) || aspace1 == aspace2) && addr2 >= addr1 && addr2 < addr1 + len1); } @@ -5617,6 +6840,7 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops, loc->ops = ops; loc->owner = owner; loc->cond = NULL; + loc->cond_bytecode = NULL; loc->shlib_disabled = 0; loc->enabled = 1; @@ -5627,6 +6851,7 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops, case bp_finish: case bp_longjmp: case bp_longjmp_resume: + case bp_longjmp_call_dummy: case bp_exception: case bp_exception_resume: case bp_step_resume: @@ -5643,10 +6868,13 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops, case bp_exception_master: case bp_gnu_ifunc_resolver: case bp_gnu_ifunc_resolver_return: + case bp_dprintf: loc->loc_type = bp_loc_software_breakpoint; + mark_breakpoint_location_modified (loc); break; case bp_hardware_breakpoint: loc->loc_type = bp_loc_hardware_breakpoint; + mark_breakpoint_location_modified (loc); break; case bp_hardware_watchpoint: case bp_read_watchpoint: @@ -5782,16 +7010,18 @@ set_breakpoint_location_function (struct bp_location *loc, int explicit_loc) || is_tracepoint (loc->owner)) { int is_gnu_ifunc; + const char *function_name; + CORE_ADDR func_addr; - find_pc_partial_function_gnu_ifunc (loc->address, &loc->function_name, - NULL, NULL, &is_gnu_ifunc); + find_pc_partial_function_gnu_ifunc (loc->address, &function_name, + &func_addr, NULL, &is_gnu_ifunc); if (is_gnu_ifunc && !explicit_loc) { struct breakpoint *b = loc->owner; gdb_assert (loc->pspace == current_program_space); - if (gnu_ifunc_resolve_name (loc->function_name, + if (gnu_ifunc_resolve_name (function_name, &loc->requested_address)) { /* Recalculate ADDRESS based on new REQUESTED_ADDRESS. */ @@ -5805,11 +7035,14 @@ set_breakpoint_location_function (struct bp_location *loc, int explicit_loc) /* Create only the whole new breakpoint of this type but do not mess more complicated breakpoints with multiple locations. */ b->type = bp_gnu_ifunc_resolver; + /* Remember the resolver's address for use by the return + breakpoint. */ + loc->related_address = func_addr; } } - if (loc->function_name) - loc->function_name = xstrdup (loc->function_name); + if (function_name) + loc->function_name = xstrdup (function_name); } } @@ -5850,8 +7083,6 @@ init_raw_breakpoint (struct breakpoint *b, struct gdbarch *gdbarch, program space. */ if (bptype != bp_breakpoint && bptype != bp_hardware_breakpoint) b->pspace = sal.pspace; - - breakpoints_changed (); } /* set_raw_breakpoint is a low level routine for allocating and @@ -5922,8 +7153,10 @@ set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame) enum bptype type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception; struct breakpoint *clone; + /* longjmp_breakpoint_ops ensures INITIATING_FRAME is cleared again + after their removal. */ clone = momentary_breakpoint_from_master (b, type, - &momentary_breakpoint_ops); + &longjmp_breakpoint_ops); clone->thread = thread; } @@ -5945,41 +7178,123 @@ delete_longjmp_breakpoint (int thread) } void -enable_overlay_breakpoints (void) +delete_longjmp_breakpoint_at_next_stop (int thread) { - struct breakpoint *b; + struct breakpoint *b, *b_tmp; - ALL_BREAKPOINTS (b) - if (b->type == bp_overlay_event) - { - b->enable_state = bp_enabled; - update_global_location_list (1); - overlay_events_enabled = 1; - } + ALL_BREAKPOINTS_SAFE (b, b_tmp) + if (b->type == bp_longjmp || b->type == bp_exception) + { + if (b->thread == thread) + b->disposition = disp_del_at_next_stop; + } } -void -disable_overlay_breakpoints (void) +/* Place breakpoints of type bp_longjmp_call_dummy to catch longjmp for + INFERIOR_PTID thread. Chain them all by RELATED_BREAKPOINT and return + pointer to any of them. Return NULL if this system cannot place longjmp + breakpoints. */ + +struct breakpoint * +set_longjmp_breakpoint_for_call_dummy (void) { - struct breakpoint *b; + struct breakpoint *b, *retval = NULL; ALL_BREAKPOINTS (b) - if (b->type == bp_overlay_event) - { - b->enable_state = bp_disabled; - update_global_location_list (0); - overlay_events_enabled = 0; - } -} + if (b->pspace == current_program_space && b->type == bp_longjmp_master) + { + struct breakpoint *new_b; -/* Set an active std::terminate breakpoint for each std::terminate - master breakpoint. */ -void -set_std_terminate_breakpoint (void) -{ - struct breakpoint *b, *b_tmp; + new_b = momentary_breakpoint_from_master (b, bp_longjmp_call_dummy, + &momentary_breakpoint_ops); + new_b->thread = pid_to_thread_id (inferior_ptid); - ALL_BREAKPOINTS_SAFE (b, b_tmp) + /* Link NEW_B into the chain of RETVAL breakpoints. */ + + gdb_assert (new_b->related_breakpoint == new_b); + if (retval == NULL) + retval = new_b; + new_b->related_breakpoint = retval; + while (retval->related_breakpoint != new_b->related_breakpoint) + retval = retval->related_breakpoint; + retval->related_breakpoint = new_b; + } + + return retval; +} + +/* Verify all existing dummy frames and their associated breakpoints for + THREAD. Remove those which can no longer be found in the current frame + stack. + + You should call this function only at places where it is safe to currently + unwind the whole stack. Failed stack unwind would discard live dummy + frames. */ + +void +check_longjmp_breakpoint_for_call_dummy (int thread) +{ + struct breakpoint *b, *b_tmp; + + ALL_BREAKPOINTS_SAFE (b, b_tmp) + if (b->type == bp_longjmp_call_dummy && b->thread == thread) + { + struct breakpoint *dummy_b = b->related_breakpoint; + + while (dummy_b != b && dummy_b->type != bp_call_dummy) + dummy_b = dummy_b->related_breakpoint; + if (dummy_b->type != bp_call_dummy + || frame_find_by_id (dummy_b->frame_id) != NULL) + continue; + + dummy_frame_discard (dummy_b->frame_id); + + while (b->related_breakpoint != b) + { + if (b_tmp == b->related_breakpoint) + b_tmp = b->related_breakpoint->next; + delete_breakpoint (b->related_breakpoint); + } + delete_breakpoint (b); + } +} + +void +enable_overlay_breakpoints (void) +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->type == bp_overlay_event) + { + b->enable_state = bp_enabled; + update_global_location_list (1); + overlay_events_enabled = 1; + } +} + +void +disable_overlay_breakpoints (void) +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->type == bp_overlay_event) + { + b->enable_state = bp_disabled; + update_global_location_list (0); + overlay_events_enabled = 0; + } +} + +/* Set an active std::terminate breakpoint for each std::terminate + master breakpoint. */ +void +set_std_terminate_breakpoint (void) +{ + struct breakpoint *b, *b_tmp; + + ALL_BREAKPOINTS_SAFE (b, b_tmp) if (b->pspace == current_program_space && b->type == bp_std_terminate_master) { @@ -6214,200 +7529,494 @@ remove_catch_fork (struct bp_location *bl) static int breakpoint_hit_catch_fork (const struct bp_location *bl, - struct address_space *aspace, CORE_ADDR bp_addr) + struct address_space *aspace, CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner; - return inferior_has_forked (inferior_ptid, &c->forked_inferior_pid); -} + if (ws->kind != TARGET_WAITKIND_FORKED) + return 0; + + c->forked_inferior_pid = ws->value.related_pid; + return 1; +} + +/* Implement the "print_it" breakpoint_ops method for fork + catchpoints. */ + +static enum print_stop_action +print_it_catch_fork (bpstat bs) +{ + struct ui_out *uiout = current_uiout; + struct breakpoint *b = bs->breakpoint_at; + struct fork_catchpoint *c = (struct fork_catchpoint *) bs->breakpoint_at; + + annotate_catchpoint (b->number); + if (b->disposition == disp_del) + ui_out_text (uiout, "\nTemporary catchpoint "); + else + ui_out_text (uiout, "\nCatchpoint "); + if (ui_out_is_mi_like_p (uiout)) + { + ui_out_field_string (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_FORK)); + ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition)); + } + ui_out_field_int (uiout, "bkptno", b->number); + ui_out_text (uiout, " (forked process "); + ui_out_field_int (uiout, "newpid", ptid_get_pid (c->forked_inferior_pid)); + ui_out_text (uiout, "), "); + return PRINT_SRC_AND_LOC; +} + +/* Implement the "print_one" breakpoint_ops method for fork + catchpoints. */ + +static void +print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc) +{ + struct fork_catchpoint *c = (struct fork_catchpoint *) b; + struct value_print_options opts; + struct ui_out *uiout = current_uiout; + + 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, "fork"); + if (!ptid_equal (c->forked_inferior_pid, null_ptid)) + { + ui_out_text (uiout, ", process "); + ui_out_field_int (uiout, "what", + ptid_get_pid (c->forked_inferior_pid)); + ui_out_spaces (uiout, 1); + } + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "catch-type", "fork"); +} + +/* Implement the "print_mention" breakpoint_ops method for fork + catchpoints. */ + +static void +print_mention_catch_fork (struct breakpoint *b) +{ + printf_filtered (_("Catchpoint %d (fork)"), b->number); +} + +/* Implement the "print_recreate" breakpoint_ops method for fork + catchpoints. */ + +static void +print_recreate_catch_fork (struct breakpoint *b, struct ui_file *fp) +{ + fprintf_unfiltered (fp, "catch fork"); + print_recreate_thread (b, fp); +} + +/* The breakpoint_ops structure to be used in fork catchpoints. */ + +static struct breakpoint_ops catch_fork_breakpoint_ops; + +/* Implement the "insert" breakpoint_ops method for vfork + catchpoints. */ + +static int +insert_catch_vfork (struct bp_location *bl) +{ + return target_insert_vfork_catchpoint (PIDGET (inferior_ptid)); +} + +/* Implement the "remove" breakpoint_ops method for vfork + catchpoints. */ + +static int +remove_catch_vfork (struct bp_location *bl) +{ + return target_remove_vfork_catchpoint (PIDGET (inferior_ptid)); +} + +/* Implement the "breakpoint_hit" breakpoint_ops method for vfork + catchpoints. */ + +static int +breakpoint_hit_catch_vfork (const struct bp_location *bl, + struct address_space *aspace, CORE_ADDR bp_addr, + const struct target_waitstatus *ws) +{ + struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner; + + if (ws->kind != TARGET_WAITKIND_VFORKED) + return 0; + + c->forked_inferior_pid = ws->value.related_pid; + return 1; +} + +/* Implement the "print_it" breakpoint_ops method for vfork + catchpoints. */ + +static enum print_stop_action +print_it_catch_vfork (bpstat bs) +{ + struct ui_out *uiout = current_uiout; + struct breakpoint *b = bs->breakpoint_at; + struct fork_catchpoint *c = (struct fork_catchpoint *) b; + + annotate_catchpoint (b->number); + if (b->disposition == disp_del) + ui_out_text (uiout, "\nTemporary catchpoint "); + else + ui_out_text (uiout, "\nCatchpoint "); + if (ui_out_is_mi_like_p (uiout)) + { + ui_out_field_string (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_VFORK)); + ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition)); + } + ui_out_field_int (uiout, "bkptno", b->number); + ui_out_text (uiout, " (vforked process "); + ui_out_field_int (uiout, "newpid", ptid_get_pid (c->forked_inferior_pid)); + ui_out_text (uiout, "), "); + return PRINT_SRC_AND_LOC; +} + +/* Implement the "print_one" breakpoint_ops method for vfork + catchpoints. */ + +static void +print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc) +{ + struct fork_catchpoint *c = (struct fork_catchpoint *) b; + struct value_print_options opts; + struct ui_out *uiout = current_uiout; + + 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, "vfork"); + if (!ptid_equal (c->forked_inferior_pid, null_ptid)) + { + ui_out_text (uiout, ", process "); + ui_out_field_int (uiout, "what", + ptid_get_pid (c->forked_inferior_pid)); + ui_out_spaces (uiout, 1); + } + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "catch-type", "vfork"); +} + +/* Implement the "print_mention" breakpoint_ops method for vfork + catchpoints. */ + +static void +print_mention_catch_vfork (struct breakpoint *b) +{ + printf_filtered (_("Catchpoint %d (vfork)"), b->number); +} + +/* Implement the "print_recreate" breakpoint_ops method for vfork + catchpoints. */ + +static void +print_recreate_catch_vfork (struct breakpoint *b, struct ui_file *fp) +{ + fprintf_unfiltered (fp, "catch vfork"); + print_recreate_thread (b, fp); +} + +/* The breakpoint_ops structure to be used in vfork catchpoints. */ + +static struct breakpoint_ops catch_vfork_breakpoint_ops; + +/* An instance of this type is used to represent an solib catchpoint. + It includes a "struct breakpoint" as a kind of base class; users + downcast to "struct breakpoint *" when needed. A breakpoint is + really of this type iff its ops pointer points to + CATCH_SOLIB_BREAKPOINT_OPS. */ + +struct solib_catchpoint +{ + /* The base class. */ + struct breakpoint base; + + /* True for "catch load", false for "catch unload". */ + unsigned char is_load; + + /* Regular expression to match, if any. COMPILED is only valid when + REGEX is non-NULL. */ + char *regex; + regex_t compiled; +}; + +static void +dtor_catch_solib (struct breakpoint *b) +{ + struct solib_catchpoint *self = (struct solib_catchpoint *) b; + + if (self->regex) + regfree (&self->compiled); + xfree (self->regex); + + base_breakpoint_ops.dtor (b); +} + +static int +insert_catch_solib (struct bp_location *ignore) +{ + return 0; +} + +static int +remove_catch_solib (struct bp_location *ignore) +{ + return 0; +} + +static int +breakpoint_hit_catch_solib (const struct bp_location *bl, + struct address_space *aspace, + CORE_ADDR bp_addr, + const struct target_waitstatus *ws) +{ + struct solib_catchpoint *self = (struct solib_catchpoint *) bl->owner; + struct breakpoint *other; + + if (ws->kind == TARGET_WAITKIND_LOADED) + return 1; + + ALL_BREAKPOINTS (other) + { + struct bp_location *other_bl; + + if (other == bl->owner) + continue; + + if (other->type != bp_shlib_event) + continue; + + if (self->base.pspace != NULL && other->pspace != self->base.pspace) + continue; + + for (other_bl = other->loc; other_bl != NULL; other_bl = other_bl->next) + { + if (other->ops->breakpoint_hit (other_bl, aspace, bp_addr, ws)) + return 1; + } + } + + return 0; +} + +static void +check_status_catch_solib (struct bpstats *bs) +{ + struct solib_catchpoint *self + = (struct solib_catchpoint *) bs->breakpoint_at; + int ix; + + if (self->is_load) + { + struct so_list *iter; + + for (ix = 0; + VEC_iterate (so_list_ptr, current_program_space->added_solibs, + ix, iter); + ++ix) + { + if (!self->regex + || regexec (&self->compiled, iter->so_name, 0, NULL, 0) == 0) + return; + } + } + else + { + char *iter; + + for (ix = 0; + VEC_iterate (char_ptr, current_program_space->deleted_solibs, + ix, iter); + ++ix) + { + if (!self->regex + || regexec (&self->compiled, iter, 0, NULL, 0) == 0) + return; + } + } -/* Implement the "print_it" breakpoint_ops method for fork - catchpoints. */ + bs->stop = 0; + bs->print_it = print_it_noop; +} static enum print_stop_action -print_it_catch_fork (bpstat bs) +print_it_catch_solib (bpstat bs) { - struct ui_out *uiout = current_uiout; struct breakpoint *b = bs->breakpoint_at; - struct fork_catchpoint *c = (struct fork_catchpoint *) bs->breakpoint_at; + struct ui_out *uiout = current_uiout; annotate_catchpoint (b->number); if (b->disposition == disp_del) ui_out_text (uiout, "\nTemporary catchpoint "); else ui_out_text (uiout, "\nCatchpoint "); - if (ui_out_is_mi_like_p (uiout)) - { - ui_out_field_string (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_FORK)); - ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition)); - } ui_out_field_int (uiout, "bkptno", b->number); - ui_out_text (uiout, " (forked process "); - ui_out_field_int (uiout, "newpid", ptid_get_pid (c->forked_inferior_pid)); - ui_out_text (uiout, "), "); + ui_out_text (uiout, "\n"); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition)); + print_solib_event (1); return PRINT_SRC_AND_LOC; } -/* Implement the "print_one" breakpoint_ops method for fork - catchpoints. */ - static void -print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc) +print_one_catch_solib (struct breakpoint *b, struct bp_location **locs) { - struct fork_catchpoint *c = (struct fork_catchpoint *) b; + struct solib_catchpoint *self = (struct solib_catchpoint *) b; struct value_print_options opts; struct ui_out *uiout = current_uiout; + char *msg; 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 (4); + ui_out_field_skip (uiout, "addr"); + } + annotate_field (5); - ui_out_text (uiout, "fork"); - if (!ptid_equal (c->forked_inferior_pid, null_ptid)) + if (self->is_load) { - ui_out_text (uiout, ", process "); - ui_out_field_int (uiout, "what", - ptid_get_pid (c->forked_inferior_pid)); - ui_out_spaces (uiout, 1); + if (self->regex) + msg = xstrprintf (_("load of library matching %s"), self->regex); + else + msg = xstrdup (_("load of library")); } -} + else + { + if (self->regex) + msg = xstrprintf (_("unload of library matching %s"), self->regex); + else + msg = xstrdup (_("unload of library")); + } + ui_out_field_string (uiout, "what", msg); + xfree (msg); -/* Implement the "print_mention" breakpoint_ops method for fork - catchpoints. */ + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "catch-type", + self->is_load ? "load" : "unload"); +} static void -print_mention_catch_fork (struct breakpoint *b) +print_mention_catch_solib (struct breakpoint *b) { - printf_filtered (_("Catchpoint %d (fork)"), b->number); -} + struct solib_catchpoint *self = (struct solib_catchpoint *) b; -/* Implement the "print_recreate" breakpoint_ops method for fork - catchpoints. */ + printf_filtered (_("Catchpoint %d (%s)"), b->number, + self->is_load ? "load" : "unload"); +} static void -print_recreate_catch_fork (struct breakpoint *b, struct ui_file *fp) +print_recreate_catch_solib (struct breakpoint *b, struct ui_file *fp) { - fprintf_unfiltered (fp, "catch fork"); - print_recreate_thread (b, fp); -} + struct solib_catchpoint *self = (struct solib_catchpoint *) b; -/* The breakpoint_ops structure to be used in fork catchpoints. */ + fprintf_unfiltered (fp, "%s %s", + b->disposition == disp_del ? "tcatch" : "catch", + self->is_load ? "load" : "unload"); + if (self->regex) + fprintf_unfiltered (fp, " %s", self->regex); + fprintf_unfiltered (fp, "\n"); +} -static struct breakpoint_ops catch_fork_breakpoint_ops; +static struct breakpoint_ops catch_solib_breakpoint_ops; -/* Implement the "insert" breakpoint_ops method for vfork - catchpoints. */ +/* Shared helper function (MI and CLI) for creating and installing + a shared object event catchpoint. If IS_LOAD is non-zero then + the events to be caught are load events, otherwise they are + unload events. If IS_TEMP is non-zero the catchpoint is a + temporary one. If ENABLED is non-zero the catchpoint is + created in an enabled state. */ -static int -insert_catch_vfork (struct bp_location *bl) +void +add_solib_catchpoint (char *arg, int is_load, int is_temp, int enabled) { - return target_insert_vfork_catchpoint (PIDGET (inferior_ptid)); -} + struct solib_catchpoint *c; + struct gdbarch *gdbarch = get_current_arch (); + struct cleanup *cleanup; -/* Implement the "remove" breakpoint_ops method for vfork - catchpoints. */ + if (!arg) + arg = ""; + arg = skip_spaces (arg); -static int -remove_catch_vfork (struct bp_location *bl) -{ - return target_remove_vfork_catchpoint (PIDGET (inferior_ptid)); -} + c = XCNEW (struct solib_catchpoint); + cleanup = make_cleanup (xfree, c); -/* Implement the "breakpoint_hit" breakpoint_ops method for vfork - catchpoints. */ + if (*arg != '\0') + { + int errcode; -static int -breakpoint_hit_catch_vfork (const struct bp_location *bl, - struct address_space *aspace, CORE_ADDR bp_addr) -{ - struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner; + errcode = regcomp (&c->compiled, arg, REG_NOSUB); + if (errcode != 0) + { + char *err = get_regcomp_error (errcode, &c->compiled); - return inferior_has_vforked (inferior_ptid, &c->forked_inferior_pid); -} + make_cleanup (xfree, err); + error (_("Invalid regexp (%s): %s"), err, arg); + } + c->regex = xstrdup (arg); + } -/* Implement the "print_it" breakpoint_ops method for vfork - catchpoints. */ + c->is_load = is_load; + init_catchpoint (&c->base, gdbarch, is_temp, NULL, + &catch_solib_breakpoint_ops); -static enum print_stop_action -print_it_catch_vfork (bpstat bs) -{ - struct ui_out *uiout = current_uiout; - struct breakpoint *b = bs->breakpoint_at; - struct fork_catchpoint *c = (struct fork_catchpoint *) b; + c->base.enable_state = enabled ? bp_enabled : bp_disabled; - annotate_catchpoint (b->number); - if (b->disposition == disp_del) - ui_out_text (uiout, "\nTemporary catchpoint "); - else - ui_out_text (uiout, "\nCatchpoint "); - if (ui_out_is_mi_like_p (uiout)) - { - ui_out_field_string (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_VFORK)); - ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition)); - } - ui_out_field_int (uiout, "bkptno", b->number); - ui_out_text (uiout, " (vforked process "); - ui_out_field_int (uiout, "newpid", ptid_get_pid (c->forked_inferior_pid)); - ui_out_text (uiout, "), "); - return PRINT_SRC_AND_LOC; + discard_cleanups (cleanup); + install_breakpoint (0, &c->base, 1); } -/* Implement the "print_one" breakpoint_ops method for vfork - catchpoints. */ +/* A helper function that does all the work for "catch load" and + "catch unload". */ static void -print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc) +catch_load_or_unload (char *arg, int from_tty, int is_load, + struct cmd_list_element *command) { - struct fork_catchpoint *c = (struct fork_catchpoint *) b; - struct value_print_options opts; - struct ui_out *uiout = current_uiout; + int tempflag; + const int enabled = 1; - 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, "vfork"); - if (!ptid_equal (c->forked_inferior_pid, null_ptid)) - { - ui_out_text (uiout, ", process "); - ui_out_field_int (uiout, "what", - ptid_get_pid (c->forked_inferior_pid)); - ui_out_spaces (uiout, 1); - } -} + tempflag = get_cmd_context (command) == CATCH_TEMPORARY; -/* Implement the "print_mention" breakpoint_ops method for vfork - catchpoints. */ + add_solib_catchpoint (arg, is_load, tempflag, enabled); +} static void -print_mention_catch_vfork (struct breakpoint *b) +catch_load_command_1 (char *arg, int from_tty, + struct cmd_list_element *command) { - printf_filtered (_("Catchpoint %d (vfork)"), b->number); + catch_load_or_unload (arg, from_tty, 1, command); } -/* Implement the "print_recreate" breakpoint_ops method for vfork - catchpoints. */ - static void -print_recreate_catch_vfork (struct breakpoint *b, struct ui_file *fp) +catch_unload_command_1 (char *arg, int from_tty, + struct cmd_list_element *command) { - fprintf_unfiltered (fp, "catch vfork"); - print_recreate_thread (b, fp); + catch_load_or_unload (arg, from_tty, 0, command); } -/* The breakpoint_ops structure to be used in vfork catchpoints. */ - -static struct breakpoint_ops catch_vfork_breakpoint_ops; - /* An instance of this type is used to represent a syscall catchpoint. It includes a "struct breakpoint" as a kind of base class; users downcast to "struct breakpoint *" when needed. A breakpoint is @@ -6439,6 +8048,47 @@ dtor_catch_syscall (struct breakpoint *b) base_breakpoint_ops.dtor (b); } +static const struct inferior_data *catch_syscall_inferior_data = NULL; + +struct catch_syscall_inferior_data +{ + /* 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. */ + int any_syscall_count; + + /* Count of each system call. */ + VEC(int) *syscalls_counts; + + /* This counts all syscall catch requests, so we can readily determine + if any catching is necessary. */ + int total_syscalls_count; +}; + +static struct catch_syscall_inferior_data* +get_catch_syscall_inferior_data (struct inferior *inf) +{ + struct catch_syscall_inferior_data *inf_data; + + inf_data = inferior_data (inf, catch_syscall_inferior_data); + if (inf_data == NULL) + { + inf_data = XZALLOC (struct catch_syscall_inferior_data); + set_inferior_data (inf, catch_syscall_inferior_data, inf_data); + } + + return inf_data; +} + +static void +catch_syscall_inferior_data_cleanup (struct inferior *inf, void *arg) +{ + xfree (arg); +} + + /* Implement the "insert" breakpoint_ops method for syscall catchpoints. */ @@ -6447,10 +8097,12 @@ insert_catch_syscall (struct bp_location *bl) { struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner; struct inferior *inf = current_inferior (); + struct catch_syscall_inferior_data *inf_data + = get_catch_syscall_inferior_data (inf); - ++inf->total_syscalls_count; + ++inf_data->total_syscalls_count; if (!c->syscalls_to_be_caught) - ++inf->any_syscall_count; + ++inf_data->any_syscall_count; else { int i, iter; @@ -6461,28 +8113,31 @@ insert_catch_syscall (struct bp_location *bl) { int elem; - if (iter >= VEC_length (int, inf->syscalls_counts)) + if (iter >= VEC_length (int, inf_data->syscalls_counts)) { - int old_size = VEC_length (int, inf->syscalls_counts); + int old_size = VEC_length (int, inf_data->syscalls_counts); uintptr_t vec_addr_offset = old_size * ((uintptr_t) sizeof (int)); uintptr_t vec_addr; - VEC_safe_grow (int, inf->syscalls_counts, iter + 1); - vec_addr = (uintptr_t) VEC_address (int, inf->syscalls_counts) + - vec_addr_offset; + VEC_safe_grow (int, inf_data->syscalls_counts, iter + 1); + vec_addr = ((uintptr_t) VEC_address (int, + inf_data->syscalls_counts) + + vec_addr_offset); memset ((void *) vec_addr, 0, (iter + 1 - old_size) * sizeof (int)); } - elem = VEC_index (int, inf->syscalls_counts, iter); - VEC_replace (int, inf->syscalls_counts, iter, ++elem); + elem = VEC_index (int, inf_data->syscalls_counts, iter); + VEC_replace (int, inf_data->syscalls_counts, iter, ++elem); } } return target_set_syscall_catchpoint (PIDGET (inferior_ptid), - inf->total_syscalls_count != 0, - inf->any_syscall_count, - VEC_length (int, inf->syscalls_counts), - VEC_address (int, inf->syscalls_counts)); + inf_data->total_syscalls_count != 0, + inf_data->any_syscall_count, + VEC_length (int, + inf_data->syscalls_counts), + VEC_address (int, + inf_data->syscalls_counts)); } /* Implement the "remove" breakpoint_ops method for syscall @@ -6493,10 +8148,12 @@ remove_catch_syscall (struct bp_location *bl) { struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner; struct inferior *inf = current_inferior (); + struct catch_syscall_inferior_data *inf_data + = get_catch_syscall_inferior_data (inf); - --inf->total_syscalls_count; + --inf_data->total_syscalls_count; if (!c->syscalls_to_be_caught) - --inf->any_syscall_count; + --inf_data->any_syscall_count; else { int i, iter; @@ -6506,20 +8163,21 @@ remove_catch_syscall (struct bp_location *bl) i++) { int elem; - if (iter >= VEC_length (int, inf->syscalls_counts)) + if (iter >= VEC_length (int, inf_data->syscalls_counts)) /* Shouldn't happen. */ continue; - elem = VEC_index (int, inf->syscalls_counts, iter); - VEC_replace (int, inf->syscalls_counts, iter, --elem); + elem = VEC_index (int, inf_data->syscalls_counts, iter); + VEC_replace (int, inf_data->syscalls_counts, iter, --elem); } } return target_set_syscall_catchpoint (PIDGET (inferior_ptid), - inf->total_syscalls_count != 0, - inf->any_syscall_count, - VEC_length (int, inf->syscalls_counts), + inf_data->total_syscalls_count != 0, + inf_data->any_syscall_count, + VEC_length (int, + inf_data->syscalls_counts), VEC_address (int, - inf->syscalls_counts)); + inf_data->syscalls_counts)); } /* Implement the "breakpoint_hit" breakpoint_ops method for syscall @@ -6527,7 +8185,8 @@ remove_catch_syscall (struct bp_location *bl) static int breakpoint_hit_catch_syscall (const struct bp_location *bl, - struct address_space *aspace, CORE_ADDR bp_addr) + struct address_space *aspace, CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { /* We must check if we are catching specific syscalls in this breakpoint. If we are, then we must guarantee that the called @@ -6536,9 +8195,12 @@ breakpoint_hit_catch_syscall (const struct bp_location *bl, const struct syscall_catchpoint *c = (const struct syscall_catchpoint *) bl->owner; - if (!inferior_has_called_syscall (inferior_ptid, &syscall_number)) + if (ws->kind != TARGET_WAITKIND_SYSCALL_ENTRY + && ws->kind != TARGET_WAITKIND_SYSCALL_RETURN) return 0; + syscall_number = ws->value.syscall_number; + /* Now, checking if the syscall is the same. */ if (c->syscalls_to_be_caught) { @@ -6572,7 +8234,6 @@ print_it_catch_syscall (bpstat bs) ptid_t ptid; struct target_waitstatus last; struct syscall s; - char *syscall_id; get_last_target_status (&ptid, &last); @@ -6664,6 +8325,9 @@ print_one_catch_syscall (struct breakpoint *b, else ui_out_field_string (uiout, "what", ""); ui_out_text (uiout, "\" "); + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "catch-type", "syscall"); } /* Implement the "print_mention" breakpoint_ops method for syscall @@ -6749,7 +8413,7 @@ syscall_catchpoint_p (struct breakpoint *b) not NULL, then store it in the breakpoint. OPS, if not NULL, is the breakpoint_ops structure associated to the catchpoint. */ -static void +void init_catchpoint (struct breakpoint *b, struct gdbarch *gdbarch, int tempflag, char *cond_string, @@ -6771,6 +8435,8 @@ install_breakpoint (int internal, struct breakpoint *b, int update_gll) { add_to_breakpoint_chain (b); set_breakpoint_number (internal, b); + if (is_tracepoint (b)) + set_tracepoint_count (breakpoint_count); if (!internal) mention (b); observer_notify_breakpoint_created (b); @@ -6839,11 +8505,16 @@ remove_catch_exec (struct bp_location *bl) static int breakpoint_hit_catch_exec (const struct bp_location *bl, - struct address_space *aspace, CORE_ADDR bp_addr) + struct address_space *aspace, CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { struct exec_catchpoint *c = (struct exec_catchpoint *) bl->owner; - return inferior_has_execd (inferior_ptid, &c->exec_pathname); + if (ws->kind != TARGET_WAITKIND_EXECD) + return 0; + + c->exec_pathname = xstrdup (ws->value.execd_pathname); + return 1; } static enum print_stop_action @@ -6894,6 +8565,9 @@ print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc) ui_out_field_string (uiout, "what", c->exec_pathname); ui_out_text (uiout, "\" "); } + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "catch-type", "exec"); } static void @@ -7055,9 +8729,9 @@ set_momentary_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal, { 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)); + /* If FRAME_ID is valid, it should be a real frame, not an inlined or + tail-called one. */ + gdb_assert (!frame_id_artificial_p (frame_id)); b = set_raw_breakpoint (gdbarch, sal, type, &momentary_breakpoint_ops); b->enable_state = bp_enabled; @@ -7095,11 +8769,9 @@ momentary_breakpoint_from_master (struct breakpoint *orig, copy->loc->address = orig->loc->address; copy->loc->section = orig->loc->section; copy->loc->pspace = orig->loc->pspace; - - if (orig->loc->source_file != NULL) - copy->loc->source_file = xstrdup (orig->loc->source_file); - + copy->loc->probe = orig->loc->probe; copy->loc->line_number = orig->loc->line_number; + copy->loc->symtab = orig->loc->symtab; copy->frame_id = orig->frame_id; copy->thread = orig->thread; copy->pspace = orig->pspace; @@ -7172,21 +8844,23 @@ add_location_to_breakpoint (struct breakpoint *b, adjusted_address = adjust_breakpoint_address (loc_gdbarch, sal->pc, b->type); + /* Sort the locations by their ADDRESS. */ loc = allocate_bp_location (b); - for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next)) + for (tmp = &(b->loc); *tmp != NULL && (*tmp)->address <= adjusted_address; + tmp = &((*tmp)->next)) ; + loc->next = *tmp; *tmp = loc; loc->requested_address = sal->pc; loc->address = adjusted_address; loc->pspace = sal->pspace; + loc->probe = sal->probe; gdb_assert (loc->pspace != NULL); loc->section = sal->section; loc->gdbarch = loc_gdbarch; - - if (sal->symtab != NULL) - loc->source_file = xstrdup (sal->symtab->filename); loc->line_number = sal->line; + loc->symtab = sal->symtab; set_breakpoint_location_function (loc, sal->explicit_pc || sal->explicit_line); @@ -7235,7 +8909,92 @@ bp_loc_is_permanent (struct bp_location *loc) return retval; } +/* Build a command list for the dprintf corresponding to the current + settings of the dprintf style options. */ + +static void +update_dprintf_command_list (struct breakpoint *b) +{ + char *dprintf_args = b->extra_string; + char *printf_line = NULL; + + if (!dprintf_args) + return; + + dprintf_args = skip_spaces (dprintf_args); + + /* Allow a comma, as it may have terminated a location, but don't + insist on it. */ + if (*dprintf_args == ',') + ++dprintf_args; + dprintf_args = skip_spaces (dprintf_args); + + if (*dprintf_args != '"') + error (_("Bad format string, missing '\"'.")); + + if (strcmp (dprintf_style, dprintf_style_gdb) == 0) + printf_line = xstrprintf ("printf %s", dprintf_args); + else if (strcmp (dprintf_style, dprintf_style_call) == 0) + { + if (!dprintf_function) + error (_("No function supplied for dprintf call")); + + if (dprintf_channel && strlen (dprintf_channel) > 0) + printf_line = xstrprintf ("call (void) %s (%s,%s)", + dprintf_function, + dprintf_channel, + dprintf_args); + else + printf_line = xstrprintf ("call (void) %s (%s)", + dprintf_function, + dprintf_args); + } + else if (strcmp (dprintf_style, dprintf_style_agent) == 0) + { + if (target_can_run_breakpoint_commands ()) + printf_line = xstrprintf ("agent-printf %s", dprintf_args); + else + { + warning (_("Target cannot run dprintf commands, falling back to GDB printf")); + printf_line = xstrprintf ("printf %s", dprintf_args); + } + } + else + internal_error (__FILE__, __LINE__, + _("Invalid dprintf style.")); + + gdb_assert (printf_line != NULL); + /* Manufacture a printf sequence. */ + { + struct command_line *printf_cmd_line + = xmalloc (sizeof (struct command_line)); + + printf_cmd_line = xmalloc (sizeof (struct command_line)); + printf_cmd_line->control_type = simple_control; + printf_cmd_line->body_count = 0; + printf_cmd_line->body_list = NULL; + printf_cmd_line->next = NULL; + printf_cmd_line->line = printf_line; + + breakpoint_set_commands (b, printf_cmd_line); + } +} + +/* Update all dprintf commands, making their command lists reflect + current style settings. */ + +static void +update_dprintf_commands (char *args, int from_tty, + struct cmd_list_element *c) +{ + struct breakpoint *b; + ALL_BREAKPOINTS (b) + { + if (b->type == bp_dprintf) + update_dprintf_command_list (b); + } +} /* Create a breakpoint with SAL as location. Use ADDR_STRING as textual description of the location, and COND_STRING @@ -7245,10 +9004,11 @@ static void init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch, struct symtabs_and_lines sals, char *addr_string, char *filter, char *cond_string, + char *extra_string, enum bptype type, enum bpdisp disposition, int thread, int task, int ignore_count, const struct breakpoint_ops *ops, int from_tty, - int enabled, int internal, unsigned flags, + int enabled, int internal, unsigned flags, int display_canonical) { int i; @@ -7289,8 +9049,9 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch, init_raw_breakpoint (b, gdbarch, sal, type, ops); b->thread = thread; b->task = task; - + b->cond_string = cond_string; + b->extra_string = extra_string; b->ignore_count = ignore_count; b->enable_state = enabled ? bp_enabled : bp_disabled; b->disposition = disposition; @@ -7303,7 +9064,7 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch, struct tracepoint *t = (struct tracepoint *) b; struct static_tracepoint_marker marker; - if (is_marker_spec (addr_string)) + if (strace_marker_p (b)) { /* We already know the marker exists, otherwise, we wouldn't see a sal for it. */ @@ -7350,12 +9111,26 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch, if (b->cond_string) { - char *arg = b->cond_string; - loc->cond = parse_exp_1 (&arg, block_for_pc (loc->address), 0); + const char *arg = b->cond_string; + + loc->cond = parse_exp_1 (&arg, loc->address, + block_for_pc (loc->address), 0); if (*arg) - error (_("Garbage %s follows condition"), arg); + error (_("Garbage '%s' follows condition"), arg); + } + + /* Dynamic printf requires and uses additional arguments on the + command line, otherwise it's an error. */ + if (type == bp_dprintf) + { + if (b->extra_string) + update_dprintf_command_list (b); + else + error (_("Format string required")); } - } + else if (b->extra_string) + error (_("Garbage '%s' at end of command"), b->extra_string); + } b->display_canonical = display_canonical; if (addr_string) @@ -7372,6 +9147,7 @@ static void create_breakpoint_sal (struct gdbarch *gdbarch, struct symtabs_and_lines sals, char *addr_string, char *filter, char *cond_string, + char *extra_string, enum bptype type, enum bpdisp disposition, int thread, int task, int ignore_count, const struct breakpoint_ops *ops, int from_tty, @@ -7395,7 +9171,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch, init_breakpoint_sal (b, gdbarch, sals, addr_string, - filter, cond_string, + filter, cond_string, extra_string, type, disposition, thread, task, ignore_count, ops, from_tty, @@ -7424,7 +9200,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch, static void create_breakpoints_sal (struct gdbarch *gdbarch, struct linespec_result *canonical, - char *cond_string, + char *cond_string, char *extra_string, enum bptype type, enum bpdisp disposition, int thread, int task, int ignore_count, const struct breakpoint_ops *ops, int from_tty, @@ -7450,7 +9226,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch, create_breakpoint_sal (gdbarch, lsal->sals, addr_string, filter_string, - cond_string, type, disposition, + cond_string, extra_string, + type, disposition, thread, task, ignore_count, ops, from_tty, enabled, internal, flags, canonical->special_display); @@ -7470,8 +9247,6 @@ static void parse_breakpoint_sals (char **address, struct linespec_result *canonical) { - char *addr_start = *address; - /* If no arg given, or if first arg is 'if ', use the default breakpoint. */ if ((*address) == NULL @@ -7483,21 +9258,27 @@ parse_breakpoint_sals (char **address, { struct linespec_sals lsal; struct symtab_and_line sal; + CORE_ADDR pc; init_sal (&sal); /* Initialize to zeroes. */ lsal.sals.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line)); /* Set sal's pspace, pc, symtab, and line to the values - corresponding to the last call to print_frame_info. */ + corresponding to the last call to print_frame_info. + Be sure to reinitialize LINE with NOTCURRENT == 0 + as the breakpoint line number is inappropriate otherwise. + find_pc_line would adjust PC, re-set it back. */ get_last_displayed_sal (&sal); - sal.section = find_pc_overlay (sal.pc); + pc = sal.pc; + sal = find_pc_line (pc, 0); /* "break" without arguments is equivalent to "break *PC" where PC is the last displayed codepoint's address. So make sure to set sal.explicit_pc to prevent GDB from trying to expand the list of sals to include all other instances with the same symtab and line. */ + sal.pc = pc; sal.explicit_pc = 1; lsal.sals.sals[0] = sal; @@ -7511,19 +9292,26 @@ parse_breakpoint_sals (char **address, } else { + struct symtab_and_line cursal = get_current_source_symtab_and_line (); + /* Force almost all breakpoints to be in terms of the current_source_symtab (which is decode_line_1's default). This should produce the results we want almost all of the - time while leaving default_breakpoint_* alone. */ - if (last_displayed_sal_is_valid ()) + time while leaving default_breakpoint_* alone. + + ObjC: However, don't match an Objective-C method name which + may have a '+' or '-' succeeded by a '['. */ + if (last_displayed_sal_is_valid () + && (!cursal.symtab + || ((strchr ("+-", (*address)[0]) != NULL) + && ((*address)[1] != '[')))) decode_line_full (address, DECODE_LINE_FUNFIRSTLINE, get_last_displayed_symtab (), get_last_displayed_line (), canonical, NULL, NULL); else decode_line_full (address, DECODE_LINE_FUNFIRSTLINE, - (struct symtab *) NULL, 0, - canonical, NULL, NULL); + cursal.symtab, cursal.line, canonical, NULL, NULL); } } @@ -7579,65 +9367,88 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch, } } +/* Issue an invalid thread ID error. */ + +static void ATTRIBUTE_NORETURN +invalid_thread_id_error (int id) +{ + error (_("Unknown thread %d."), id); +} + /* Given TOK, a string specification of condition and thread, as accepted by the 'break' command, extract the condition string and thread number and set *COND_STRING and *THREAD. PC identifies the context at which the condition should be parsed. If no condition is found, *COND_STRING is set to NULL. If no thread is found, *THREAD is set to -1. */ -static void -find_condition_and_thread (char *tok, CORE_ADDR pc, - char **cond_string, int *thread, int *task) + +static void +find_condition_and_thread (const char *tok, CORE_ADDR pc, + char **cond_string, int *thread, int *task, + char **rest) { *cond_string = NULL; *thread = -1; + *task = 0; + *rest = NULL; + while (tok && *tok) { - char *end_tok; + const char *end_tok; int toklen; - char *cond_start = NULL; - char *cond_end = NULL; + const char *cond_start = NULL; + const char *cond_end = NULL; + + tok = skip_spaces_const (tok); + + if ((*tok == '"' || *tok == ',') && rest) + { + *rest = savestring (tok, strlen (tok)); + return; + } + + end_tok = skip_to_space_const (tok); - tok = skip_spaces (tok); - - end_tok = skip_to_space (tok); - toklen = end_tok - tok; - + if (toklen >= 1 && strncmp (tok, "if", toklen) == 0) { struct expression *expr; tok = cond_start = end_tok + 1; - expr = parse_exp_1 (&tok, block_for_pc (pc), 0); + expr = parse_exp_1 (&tok, pc, block_for_pc (pc), 0); xfree (expr); cond_end = tok; - *cond_string = savestring (cond_start, - cond_end - cond_start); + *cond_string = savestring (cond_start, cond_end - cond_start); } else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0) { char *tmptok; - + tok = end_tok + 1; - tmptok = tok; - *thread = strtol (tok, &tok, 0); + *thread = strtol (tok, &tmptok, 0); if (tok == tmptok) error (_("Junk after thread keyword.")); if (!valid_thread_id (*thread)) - error (_("Unknown thread %d."), *thread); + invalid_thread_id_error (*thread); + tok = tmptok; } else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0) { char *tmptok; tok = end_tok + 1; - tmptok = tok; - *task = strtol (tok, &tok, 0); + *task = strtol (tok, &tmptok, 0); if (tok == tmptok) error (_("Junk after task keyword.")); if (!valid_task_id (*task)) error (_("Unknown task %d."), *task); + tok = tmptok; + } + else if (rest) + { + *rest = savestring (tok, strlen (tok)); + return; } else error (_("Junk at end of arguments.")); @@ -7651,8 +9462,6 @@ decode_static_tracepoint_spec (char **arg_p) { VEC(static_tracepoint_marker_p) *markers = NULL; struct symtabs_and_lines sals; - struct symtab_and_line sal; - struct symbol *sym; struct cleanup *old_chain; char *p = &(*arg_p)[3]; char *endp; @@ -7706,7 +9515,8 @@ decode_static_tracepoint_spec (char **arg_p) int create_breakpoint (struct gdbarch *gdbarch, - char *arg, char *cond_string, int thread, + char *arg, char *cond_string, + int thread, char *extra_string, int parse_condition_and_thread, int tempflag, enum bptype type_wanted, int ignore_count, @@ -7721,7 +9531,6 @@ create_breakpoint (struct gdbarch *gdbarch, struct linespec_result canonical; struct cleanup *old_chain; struct cleanup *bkpt_chain = NULL; - int i; int pending = 0; int task = 0; int prev_bkpt_count = breakpoint_count; @@ -7730,32 +9539,19 @@ create_breakpoint (struct gdbarch *gdbarch, init_linespec_result (&canonical); - if (type_wanted == bp_static_tracepoint && is_marker_spec (arg)) - { - int i; - struct linespec_sals lsal; - - lsal.sals = decode_static_tracepoint_spec (&arg); - - copy_arg = savestring (addr_start, arg - addr_start); - - canonical.addr_string = xstrdup (copy_arg); - lsal.canonical = xstrdup (copy_arg); - VEC_safe_push (linespec_sals, canonical.sals, &lsal); - - goto done; - } - TRY_CATCH (e, RETURN_MASK_ALL) { - parse_breakpoint_sals (&arg, &canonical); + ops->create_sals_from_address (&arg, &canonical, type_wanted, + addr_start, ©_arg); } /* If caller is interested in rc value from parse, set value. */ switch (e.reason) { - case RETURN_QUIT: - throw_exception (e); + case GDB_NO_ERROR: + if (VEC_empty (linespec_sals, canonical.sals)) + return 0; + break; case RETURN_ERROR: switch (e.error) { @@ -7797,12 +9593,9 @@ create_breakpoint (struct gdbarch *gdbarch, } break; default: - if (VEC_empty (linespec_sals, canonical.sals)) - return 0; + throw_exception (e); } - done: - /* Create a chain of things that always need to be cleaned up. */ old_chain = make_cleanup_destroy_linespec_result (&canonical); @@ -7844,16 +9637,20 @@ create_breakpoint (struct gdbarch *gdbarch, if (parse_condition_and_thread) { + char *rest; /* Here we only parse 'arg' to separate condition from thread number, so parsing in context of first sal is OK. When setting the breakpoint we'll re-parse it in context of each sal. */ - cond_string = NULL; - thread = -1; + find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string, - &thread, &task); + &thread, &task, &rest); if (cond_string) make_cleanup (xfree, cond_string); + if (rest) + make_cleanup (xfree, rest); + if (rest) + extra_string = rest; } else { @@ -7863,59 +9660,19 @@ create_breakpoint (struct gdbarch *gdbarch, cond_string = xstrdup (cond_string); make_cleanup (xfree, cond_string); } + /* Create a private copy of any extra string. */ + if (extra_string) + { + extra_string = xstrdup (extra_string); + make_cleanup (xfree, extra_string); + } } - /* If the user is creating a static tracepoint by marker id - (strace -m MARKER_ID), then store the sals index, so that - breakpoint_re_set can try to match up which of the newly - found markers corresponds to this one, and, don't try to - expand multiple locations for each sal, given than SALS - already should contain all sals for MARKER_ID. */ - if (type_wanted == bp_static_tracepoint - && is_marker_spec (copy_arg)) - { - int i; - - for (i = 0; i < lsal->sals.nelts; ++i) - { - struct symtabs_and_lines expanded; - struct tracepoint *tp; - struct cleanup *old_chain; - char *addr_string; - - expanded.nelts = 1; - expanded.sals = &lsal->sals.sals[i]; - - addr_string = xstrdup (canonical.addr_string); - old_chain = make_cleanup (xfree, addr_string); - - tp = XCNEW (struct tracepoint); - init_breakpoint_sal (&tp->base, gdbarch, expanded, - addr_string, NULL, - cond_string, type_wanted, + ops->create_breakpoints_sal (gdbarch, &canonical, lsal, + cond_string, extra_string, type_wanted, tempflag ? disp_del : disp_donttouch, thread, task, ignore_count, ops, - from_tty, enabled, internal, flags, - canonical.special_display); - /* Given that its possible to have multiple markers with - the same string id, if the user is creating a static - tracepoint by marker id ("strace -m MARKER_ID"), then - store the sals index, so that breakpoint_re_set can - try to match up which of the newly found markers - corresponds to this one */ - tp->static_trace_marker_id_idx = i; - - install_breakpoint (internal, &tp->base, 0); - - discard_cleanups (old_chain); - } - } - else - create_breakpoints_sal (gdbarch, &canonical, cond_string, - type_wanted, - tempflag ? disp_del : disp_donttouch, - thread, task, ignore_count, ops, from_tty, - enabled, internal, flags); + from_tty, enabled, internal, flags); } else { @@ -7936,7 +9693,19 @@ create_breakpoint (struct gdbarch *gdbarch, init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops); b->addr_string = copy_arg; - b->cond_string = NULL; + if (parse_condition_and_thread) + b->cond_string = NULL; + else + { + /* Create a private copy of condition string. */ + if (cond_string) + { + cond_string = xstrdup (cond_string); + make_cleanup (xfree, cond_string); + } + b->cond_string = cond_string; + } + b->extra_string = NULL; b->ignore_count = ignore_count; b->disposition = tempflag ? disp_del : disp_donttouch; b->condition_not_parsed = 1; @@ -7981,14 +9750,22 @@ break_command_1 (char *arg, int flag, int from_tty) enum bptype type_wanted = (flag & BP_HARDWAREFLAG ? bp_hardware_breakpoint : bp_breakpoint); + struct breakpoint_ops *ops; + const char *arg_cp = arg; + + /* Matching breakpoints on probes. */ + if (arg && probe_linespec_to_ops (&arg_cp) != NULL) + ops = &bkpt_probe_breakpoint_ops; + else + ops = &bkpt_breakpoint_ops; create_breakpoint (get_current_arch (), arg, - NULL, 0, 1 /* parse arg */, + NULL, 0, NULL, 1 /* parse arg */, tempflag, type_wanted, 0 /* Ignore count */, pending_break_support, - &bkpt_breakpoint_ops, + ops, from_tty, 1 /* enabled */, 0 /* internal */, @@ -8006,7 +9783,7 @@ resolve_sal_pc (struct symtab_and_line *sal) { if (!find_line_pc (sal->symtab, sal->line, &pc)) error (_("No line %d in file \"%s\"."), - sal->line, sal->symtab->filename); + sal->line, symtab_to_filename_for_display (sal->symtab)); sal->pc = pc; /* If this SAL corresponds to a breakpoint inserted using a line @@ -8149,14 +9926,46 @@ stopat_command (char *arg, int from_tty) break_command_1 (arg, 0, from_tty); } +/* The dynamic printf command is mostly like a regular breakpoint, but + with a prewired command list consisting of a single output command, + built from extra arguments supplied on the dprintf command + line. */ + +static void +dprintf_command (char *arg, int from_tty) +{ + create_breakpoint (get_current_arch (), + arg, + NULL, 0, NULL, 1 /* parse arg */, + 0, bp_dprintf, + 0 /* Ignore count */, + pending_break_support, + &dprintf_breakpoint_ops, + from_tty, + 1 /* enabled */, + 0 /* internal */, + 0); +} + +static void +agent_printf_command (char *arg, int from_tty) +{ + error (_("May only run agent-printf on the target")); +} + /* Implement the "breakpoint_hit" breakpoint_ops method for ranged breakpoints. */ static int breakpoint_hit_ranged_breakpoint (const struct bp_location *bl, struct address_space *aspace, - CORE_ADDR bp_addr) + CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { + if (ws->kind != TARGET_WAITKIND_STOPPED + || ws->value.sig != GDB_SIGNAL_TRAP) + return 0; + return breakpoint_address_match_range (bl->pspace->aspace, bl->address, bl->length, aspace, bp_addr); } @@ -8236,8 +10045,8 @@ print_one_detail_ranged_breakpoint (const struct breakpoint *b, { CORE_ADDR address_start, address_end; struct bp_location *bl = b->loc; - struct ui_stream *stb = ui_out_stream_new (uiout); - struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb); + struct ui_file *stb = mem_fileopen (); + struct cleanup *cleanup = make_cleanup_ui_file_delete (stb); gdb_assert (bl); @@ -8245,7 +10054,7 @@ print_one_detail_ranged_breakpoint (const struct breakpoint *b, address_end = address_start + bl->length - 1; ui_out_text (uiout, "\taddress range: "); - fprintf_unfiltered (stb->stream, "[%s, %s]", + fprintf_unfiltered (stb, "[%s, %s]", print_core_address (bl->gdbarch, address_start), print_core_address (bl->gdbarch, address_end)); ui_out_field_stream (uiout, "addr", stb); @@ -8441,6 +10250,7 @@ break_range_command (char *arg, int from_tty) means EXP is variable. Also the constant detection may fail for some constant expressions and in such case still falsely return zero. */ + static int watchpoint_exp_is_const (const struct expression *exp) { @@ -8486,7 +10296,6 @@ watchpoint_exp_is_const (const struct expression *exp) case BINOP_RANGE: case TERNOP_COND: case TERNOP_SLICE: - case TERNOP_SLICE_COUNT: case OP_LONG: case OP_DOUBLE: @@ -8494,9 +10303,10 @@ watchpoint_exp_is_const (const struct expression *exp) case OP_LAST: case OP_COMPLEX: case OP_STRING: - case OP_BITSTRING: case OP_ARRAY: case OP_TYPE: + case OP_TYPEOF: + case OP_DECLTYPE: case OP_NAME: case OP_OBJC_NSSTRING: @@ -8505,6 +10315,11 @@ watchpoint_exp_is_const (const struct expression *exp) case UNOP_COMPLEMENT: case UNOP_ADDR: case UNOP_HIGH: + case UNOP_CAST: + + case UNOP_CAST_TYPE: + case UNOP_REINTERPRET_CAST: + case UNOP_DYNAMIC_CAST: /* Unary, binary and ternary operators: We have to check their operands. If they are constant, then so is the result of that operation. For instance, if A and B are @@ -8623,7 +10438,8 @@ remove_watchpoint (struct bp_location *bl) static int breakpoint_hit_watchpoint (const struct bp_location *bl, - struct address_space *aspace, CORE_ADDR bp_addr) + struct address_space *aspace, CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { struct breakpoint *b = bl->owner; struct watchpoint *w = (struct watchpoint *) b; @@ -8677,7 +10493,7 @@ print_it_watchpoint (bpstat bs) struct cleanup *old_chain; struct breakpoint *b; const struct bp_location *bl; - struct ui_stream *stb; + struct ui_file *stb; enum print_stop_action result; struct watchpoint *w; struct ui_out *uiout = current_uiout; @@ -8688,8 +10504,8 @@ print_it_watchpoint (bpstat bs) b = bs->breakpoint_at; w = (struct watchpoint *) b; - stb = ui_out_stream_new (uiout); - old_chain = make_cleanup_ui_out_stream_delete (stb); + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); switch (b->type) { @@ -8703,10 +10519,10 @@ print_it_watchpoint (bpstat bs) mention (b); make_cleanup_ui_out_tuple_begin_end (uiout, "value"); ui_out_text (uiout, "\nOld value = "); - watchpoint_value_print (bs->old_val, stb->stream); + watchpoint_value_print (bs->old_val, stb); ui_out_field_stream (uiout, "old", stb); ui_out_text (uiout, "\nNew value = "); - watchpoint_value_print (w->val, stb->stream); + watchpoint_value_print (w->val, stb); ui_out_field_stream (uiout, "new", stb); ui_out_text (uiout, "\n"); /* More than one watchpoint may have been triggered. */ @@ -8721,7 +10537,7 @@ print_it_watchpoint (bpstat bs) mention (b); make_cleanup_ui_out_tuple_begin_end (uiout, "value"); ui_out_text (uiout, "\nValue = "); - watchpoint_value_print (w->val, stb->stream); + watchpoint_value_print (w->val, stb); ui_out_field_stream (uiout, "value", stb); ui_out_text (uiout, "\n"); result = PRINT_UNKNOWN; @@ -8738,7 +10554,7 @@ print_it_watchpoint (bpstat bs) mention (b); make_cleanup_ui_out_tuple_begin_end (uiout, "value"); ui_out_text (uiout, "\nOld value = "); - watchpoint_value_print (bs->old_val, stb->stream); + watchpoint_value_print (bs->old_val, stb); ui_out_field_stream (uiout, "old", stb); ui_out_text (uiout, "\nNew value = "); } @@ -8752,7 +10568,7 @@ print_it_watchpoint (bpstat bs) make_cleanup_ui_out_tuple_begin_end (uiout, "value"); ui_out_text (uiout, "\nValue = "); } - watchpoint_value_print (w->val, stb->stream); + watchpoint_value_print (w->val, stb); ui_out_field_stream (uiout, "new", stb); ui_out_text (uiout, "\n"); result = PRINT_UNKNOWN; @@ -8833,6 +10649,20 @@ print_recreate_watchpoint (struct breakpoint *b, struct ui_file *fp) print_recreate_thread (b, fp); } +/* Implement the "explains_signal" breakpoint_ops method for + watchpoints. */ + +static enum bpstat_signal_value +explains_signal_watchpoint (struct breakpoint *b, enum gdb_signal sig) +{ + /* A software watchpoint cannot cause a signal other than + GDB_SIGNAL_TRAP. */ + if (b->type == bp_watchpoint && sig != GDB_SIGNAL_TRAP) + return BPSTAT_SIGNAL_NO; + + return BPSTAT_SIGNAL_HIDE; +} + /* The breakpoint_ops structure to be used in hardware watchpoints. */ static struct breakpoint_ops watchpoint_breakpoint_ops; @@ -9029,21 +10859,21 @@ is_masked_watchpoint (const struct breakpoint *b) hw_read: watch read, hw_access: watch access (read or write) */ static void -watch_command_1 (char *arg, int accessflag, int from_tty, +watch_command_1 (const char *arg, int accessflag, int from_tty, int just_location, int internal) { volatile struct gdb_exception e; struct breakpoint *b, *scope_breakpoint = NULL; struct expression *exp; - struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL; + const struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL; struct value *val, *mark, *result; struct frame_info *frame; - char *exp_start = NULL; - char *exp_end = NULL; - char *tok, *end_tok; + const char *exp_start = NULL; + const char *exp_end = NULL; + const char *tok, *end_tok; int toklen = -1; - char *cond_start = NULL; - char *cond_end = NULL; + const char *cond_start = NULL; + const char *cond_end = NULL; enum bptype bp_type; int thread = -1; int pc = 0; @@ -9052,15 +10882,19 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int use_mask = 0; CORE_ADDR mask = 0; struct watchpoint *w; + char *expression; + struct cleanup *back_to; /* Make sure that we actually have parameters to parse. */ if (arg != NULL && arg[0] != '\0') { - char *value_start; + const char *value_start; + + exp_end = arg + strlen (arg); /* Look for "parameter value" pairs at the end of the arguments string. */ - for (tok = arg + strlen (arg) - 1; tok > arg; tok--) + for (tok = exp_end - 1; tok > arg; tok--) { /* Skip whitespace at the end of the argument list. */ while (tok > arg && (*tok == ' ' || *tok == '\t')) @@ -9105,7 +10939,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty, /* Check if the thread actually exists. */ if (!valid_thread_id (thread)) - error (_("Unknown thread %d."), thread); + invalid_thread_id_error (thread); } else if (toklen == 4 && !strncmp (tok, "mask", 4)) { @@ -9130,14 +10964,20 @@ watch_command_1 (char *arg, int accessflag, int from_tty, /* Truncate the string and get rid of the "parameter value" pair before the arguments string is parsed by the parse_exp_1 function. */ - *tok = '\0'; + exp_end = tok; } } + else + exp_end = arg; - /* Parse the rest of the arguments. */ + /* Parse the rest of the arguments. From here on out, everything + is in terms of a newly allocated string instead of the original + ARG. */ innermost_block = NULL; - exp_start = arg; - exp = parse_exp_1 (&arg, 0, 0); + expression = savestring (arg, exp_end - arg); + back_to = make_cleanup (xfree, expression); + exp_start = arg = expression; + exp = parse_exp_1 (&arg, 0, 0, 0); exp_end = arg; /* Remove trailing whitespace from the expression before saving it. This makes the eventual display of the expression string a bit @@ -9182,8 +11022,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty, else if (val != NULL) release_value (val); - tok = skip_spaces (arg); - end_tok = skip_to_space (tok); + tok = skip_spaces_const (arg); + end_tok = skip_to_space_const (tok); toklen = end_tok - tok; if (toklen >= 1 && strncmp (tok, "if", toklen) == 0) @@ -9192,7 +11032,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty, innermost_block = NULL; tok = cond_start = end_tok + 1; - cond = parse_exp_1 (&tok, 0, 0); + cond = parse_exp_1 (&tok, 0, 0, 0); /* The watchpoint expression may not be local, but the condition may still be. E.g.: `watch global if local > 0'. */ @@ -9335,6 +11175,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty, } install_breakpoint (internal, b, 1); + do_cleanups (back_to); } /* Return count of debug registers needed to watch the given expression. @@ -9427,23 +11268,6 @@ watch_command_wrapper (char *arg, int from_tty, int internal) watch_command_1 (arg, hw_write, from_tty, 0, internal); } -/* A helper function that looks for an argument at the start of a - string. The argument must also either be at the end of the string, - or be followed by whitespace. Returns 1 if it finds the argument, - 0 otherwise. If the argument is found, it updates *STR. */ - -static int -check_for_argument (char **str, char *arg, int arg_len) -{ - if (strncmp (*str, arg, arg_len) == 0 - && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len]))) - { - *str += arg_len; - return 1; - } - return 0; -} - /* A helper function that looks for the "-location" argument and then calls watch_command_1. */ @@ -9524,7 +11348,10 @@ until_break_command (char *arg, int from_tty, int anywhere) { struct symtabs_and_lines sals; struct symtab_and_line sal; - struct frame_info *frame = get_selected_frame (NULL); + struct frame_info *frame; + struct gdbarch *frame_gdbarch; + struct frame_id stack_frame_id; + struct frame_id caller_frame_id; struct breakpoint *breakpoint; struct breakpoint *breakpoint2 = NULL; struct cleanup *old_chain; @@ -9555,41 +11382,56 @@ until_break_command (char *arg, int from_tty, int anywhere) resolve_sal_pc (&sal); - if (anywhere) - /* If the user told us to continue until a specified location, - we don't specify a frame at which we need to stop. */ - breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal, - null_frame_id, bp_until); - else - /* Otherwise, specify the selected frame, because we want to stop - only at the very same frame. */ - breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal, - get_stack_frame_id (frame), - bp_until); - - old_chain = make_cleanup_delete_breakpoint (breakpoint); - tp = inferior_thread (); thread = tp->num; + old_chain = make_cleanup (null_cleanup, NULL); + + /* Note linespec handling above invalidates the frame chain. + Installing a breakpoint also invalidates the frame chain (as it + may need to switch threads), so do any frame handling before + that. */ + + frame = get_selected_frame (NULL); + frame_gdbarch = get_frame_arch (frame); + stack_frame_id = get_stack_frame_id (frame); + caller_frame_id = frame_unwind_caller_id (frame); + /* Keep within the current frame, or in frames called by the current one. */ - if (frame_id_p (frame_unwind_caller_id (frame))) + if (frame_id_p (caller_frame_id)) { - sal = find_pc_line (frame_unwind_caller_pc (frame), 0); - sal.pc = frame_unwind_caller_pc (frame); + struct symtab_and_line sal2; + + sal2 = find_pc_line (frame_unwind_caller_pc (frame), 0); + sal2.pc = frame_unwind_caller_pc (frame); breakpoint2 = set_momentary_breakpoint (frame_unwind_caller_arch (frame), - sal, - frame_unwind_caller_id (frame), + sal2, + caller_frame_id, bp_until); make_cleanup_delete_breakpoint (breakpoint2); - set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame)); + set_longjmp_breakpoint (tp, caller_frame_id); make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); } - proceed (-1, TARGET_SIGNAL_DEFAULT, 0); + /* set_momentary_breakpoint could invalidate FRAME. */ + frame = NULL; + + if (anywhere) + /* If the user told us to continue until a specified location, + we don't specify a frame at which we need to stop. */ + breakpoint = set_momentary_breakpoint (frame_gdbarch, sal, + null_frame_id, bp_until); + else + /* Otherwise, specify the selected frame, because we want to stop + only at the very same frame. */ + breakpoint = set_momentary_breakpoint (frame_gdbarch, sal, + stack_frame_id, bp_until); + make_cleanup_delete_breakpoint (breakpoint); + + proceed (-1, GDB_SIGNAL_DEFAULT, 0); /* If we are running asynchronously, and proceed call above has actually managed to start the target, arrange for breakpoints to @@ -9789,9 +11631,17 @@ print_one_exception_catchpoint (struct breakpoint *b, if (b->loc) *last_loc = b->loc; if (strstr (b->addr_string, "throw") != NULL) - ui_out_field_string (uiout, "what", "exception throw"); + { + ui_out_field_string (uiout, "what", "exception throw"); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "catch-type", "throw"); + } else - ui_out_field_string (uiout, "what", "exception catch"); + { + ui_out_field_string (uiout, "what", "exception catch"); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "catch-type", "catch"); + } } static void @@ -9841,7 +11691,7 @@ handle_gnu_v3_exceptions (int tempflag, char *cond_string, trigger_func_name = "__cxa_throw"; create_breakpoint (get_current_arch (), - trigger_func_name, cond_string, -1, + trigger_func_name, cond_string, -1, NULL, 0 /* condition and thread are valid. */, tempflag, bp_breakpoint, 0, @@ -9952,8 +11802,7 @@ catch_syscall_split_args (char *arg) struct syscall s; /* Skip whitespace. */ - while (isspace (*arg)) - arg++; + arg = skip_spaces (arg); for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i) cur_name[i] = arg[i]; @@ -10058,7 +11907,7 @@ compare_breakpoints (const void *a, const void *b) the number 0. */ if (ua < ub) return -1; - return ub > ub ? 1 : 0; + return ua > ub ? 1 : 0; } /* Delete breakpoints by address or line. */ @@ -10077,8 +11926,10 @@ clear_command (char *arg, int from_tty) if (arg) { - sals = decode_line_spec (arg, (DECODE_LINE_FUNFIRSTLINE - | DECODE_LINE_LIST_MODE)); + sals = decode_line_with_current_source (arg, + (DECODE_LINE_FUNFIRSTLINE + | DECODE_LINE_LIST_MODE)); + make_cleanup (xfree, sals.sals); default_match = 0; } else @@ -10127,6 +11978,8 @@ clear_command (char *arg, int from_tty) make_cleanup (VEC_cleanup (breakpoint_p), &found); for (i = 0; i < sals.nelts; i++) { + const char *sal_fullname; + /* If exact pc given, clear bpts at that pc. If line given (pc == 0), clear all bpts on specified line. If defaulting, clear all bpts on default line @@ -10140,6 +11993,8 @@ clear_command (char *arg, int from_tty) 1 0 */ sal = sals.sals[i]; + sal_fullname = (sal.symtab == NULL + ? NULL : symtab_to_fullname (sal.symtab)); /* Find all matching breakpoints and add them to 'found'. */ ALL_BREAKPOINTS (b) @@ -10159,13 +12014,17 @@ clear_command (char *arg, int from_tty) && (loc->address == sal.pc) && (!section_is_overlay (loc->section) || loc->section == sal.section)); - int line_match = ((default_match || sal.explicit_line) - && loc->source_file != NULL - && sal.symtab != NULL - && sal.pspace == loc->pspace - && filename_cmp (loc->source_file, - sal.symtab->filename) == 0 - && loc->line_number == sal.line); + int line_match = 0; + + if ((default_match || sal.explicit_line) + && loc->symtab != NULL + && sal_fullname != NULL + && sal.pspace == loc->pspace + && loc->line_number == sal.line + && filename_cmp (symtab_to_fullname (loc->symtab), + sal_fullname) == 0) + line_match = 1; + if (pc_match || line_match) { match = 1; @@ -10212,7 +12071,6 @@ clear_command (char *arg, int from_tty) else printf_unfiltered (_("Deleted breakpoints ")); } - breakpoints_changed (); for (ix = 0; VEC_iterate(breakpoint_p, found, ix, b); ix++) { @@ -10267,16 +12125,25 @@ bp_location_compare (const void *ap, const void *bp) if (a->address != b->address) return (a->address > b->address) - (a->address < b->address); + /* Sort locations at the same address by their pspace number, keeping + locations of the same inferior (in a multi-inferior environment) + grouped. */ + + if (a->pspace->num != b->pspace->num) + return ((a->pspace->num > b->pspace->num) + - (a->pspace->num < b->pspace->num)); + /* Sort permanent breakpoints first. */ if (a_perm != b_perm) return (a_perm < b_perm) - (a_perm > b_perm); - /* Make the user-visible order stable across GDB runs. Locations of - the same breakpoint can be sorted in arbitrary order. */ + /* Make the internal GDB representation stable across GDB runs + where A and B memory inside GDB can differ. Breakpoint locations of + the same type at the same address can be sorted in arbitrary order. */ if (a->owner->number != b->owner->number) - return (a->owner->number > b->owner->number) - - (a->owner->number < b->owner->number); + return ((a->owner->number > b->owner->number) + - (a->owner->number < b->owner->number)); return (a > b) - (a < b); } @@ -10322,7 +12189,7 @@ bp_location_target_extensions_update (void) static void download_tracepoint_locations (void) { - struct bp_location *bl, **blp_tmp; + struct breakpoint *b; struct cleanup *old_chain; if (!target_can_download_tracepoint ()) @@ -10330,31 +12197,36 @@ download_tracepoint_locations (void) old_chain = save_current_space_and_thread (); - ALL_BP_LOCATIONS (bl, blp_tmp) + ALL_TRACEPOINTS (b) { + struct bp_location *bl; struct tracepoint *t; + int bp_location_downloaded = 0; - if (!is_tracepoint (bl->owner)) - continue; - - if ((bl->owner->type == bp_fast_tracepoint + if ((b->type == bp_fast_tracepoint ? !may_insert_fast_tracepoints : !may_insert_tracepoints)) continue; - /* In tracepoint, locations are _never_ duplicated, so - should_be_inserted is equivalent to - unduplicated_should_be_inserted. */ - if (!should_be_inserted (bl) || bl->inserted) - continue; + for (bl = b->loc; bl; bl = bl->next) + { + /* In tracepoint, locations are _never_ duplicated, so + should_be_inserted is equivalent to + unduplicated_should_be_inserted. */ + if (!should_be_inserted (bl) || bl->inserted) + continue; - switch_to_program_space_and_thread (bl->pspace); + switch_to_program_space_and_thread (bl->pspace); - target_download_tracepoint (bl); + target_download_tracepoint (bl); - bl->inserted = 1; - t = (struct tracepoint *) bl->owner; - t->number_on_target = bl->owner->number; + bl->inserted = 1; + bp_location_downloaded = 1; + } + t = (struct tracepoint *) b; + t->number_on_target = b->number; + if (bp_location_downloaded) + observer_notify_breakpoint_modified (b); } do_cleanups (old_chain); @@ -10367,6 +12239,7 @@ swap_insertion (struct bp_location *left, struct bp_location *right) { const int left_inserted = left->inserted; const int left_duplicate = left->duplicate; + const int left_needs_update = left->needs_update; const struct bp_target_info left_target_info = left->target_info; /* Locations of tracepoints can never be duplicated. */ @@ -10377,12 +12250,67 @@ swap_insertion (struct bp_location *left, struct bp_location *right) left->inserted = right->inserted; left->duplicate = right->duplicate; + left->needs_update = right->needs_update; left->target_info = right->target_info; right->inserted = left_inserted; right->duplicate = left_duplicate; + right->needs_update = left_needs_update; right->target_info = left_target_info; } +/* Force the re-insertion of the locations at ADDRESS. This is called + once a new/deleted/modified duplicate location is found and we are evaluating + conditions on the target's side. Such conditions need to be updated on + the target. */ + +static void +force_breakpoint_reinsertion (struct bp_location *bl) +{ + struct bp_location **locp = NULL, **loc2p; + struct bp_location *loc; + CORE_ADDR address = 0; + int pspace_num; + + address = bl->address; + pspace_num = bl->pspace->num; + + /* This is only meaningful if the target is + evaluating conditions and if the user has + opted for condition evaluation on the target's + side. */ + if (gdb_evaluates_breakpoint_condition_p () + || !target_supports_evaluation_of_breakpoint_conditions ()) + return; + + /* Flag all breakpoint locations with this address and + the same program space as the location + as "its condition has changed". We need to + update the conditions on the target's side. */ + ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, address) + { + loc = *loc2p; + + if (!is_breakpoint (loc->owner) + || pspace_num != loc->pspace->num) + continue; + + /* Flag the location appropriately. We use a different state to + let everyone know that we already updated the set of locations + with addr bl->address and program space bl->pspace. This is so + we don't have to keep calling these functions just to mark locations + that have already been marked. */ + loc->condition_changed = condition_updated; + + /* Free the agent expression bytecode as well. We will compute + it later on. */ + if (loc->cond_bytecode) + { + free_agent_expr (loc->cond_bytecode); + loc->cond_bytecode = NULL; + } + } +} + /* If SHOULD_INSERT is false, do not insert any breakpoint locations into the inferior, only remove already-inserted locations that no longer should be inserted. Functions that delete a breakpoint or @@ -10404,6 +12332,10 @@ update_global_location_list (int should_insert) struct breakpoint *b; struct bp_location **locp, *loc; struct cleanup *cleanups; + /* Last breakpoint location address that was marked for update. */ + CORE_ADDR last_addr = 0; + /* Last breakpoint location program space that was marked for update. */ + int last_pspace_num = -1; /* Used in the duplicates detection below. When iterating over all bp_locations, points to the first bp_location of a given address. @@ -10476,13 +12408,30 @@ update_global_location_list (int should_insert) && (*loc2p)->address == old_loc->address); loc2p++) { - if (*loc2p == old_loc) + /* Check if this is a new/duplicated location or a duplicated + location that had its condition modified. If so, we want to send + its condition to the target if evaluation of conditions is taking + place there. */ + if ((*loc2p)->condition_changed == condition_modified + && (last_addr != old_loc->address + || last_pspace_num != old_loc->pspace->num)) { - found_object = 1; - break; + force_breakpoint_reinsertion (*loc2p); + last_pspace_num = old_loc->pspace->num; } + + if (*loc2p == old_loc) + found_object = 1; } + /* We have already handled this address, update it so that we don't + have to go through updates again. */ + last_addr = old_loc->address; + + /* Target-side condition evaluation: Handle deleted locations. */ + if (!found_object) + force_breakpoint_reinsertion (old_loc); + /* If this location is no longer present, and inserted, look if there's maybe a new location at the same address. If so, mark that one inserted, and don't remove this one. This is @@ -10502,6 +12451,10 @@ update_global_location_list (int should_insert) } else { + /* This location still exists, but it won't be kept in the + target since it may have been disabled. We proceed to + remove its target-side condition. */ + /* The location is either no longer present, or got disabled. See if there's another location at the same address, in which case we don't need to remove @@ -10648,13 +12601,17 @@ update_global_location_list (int should_insert) struct bp_location **loc_first_p; b = loc->owner; - if (!should_be_inserted (loc) + if (!unduplicated_should_be_inserted (loc) || !breakpoint_address_is_meaningful (b) /* Don't detect duplicate for tracepoint locations because they are never duplicated. See the comments in field `duplicate' of `struct bp_location'. */ || is_tracepoint (b)) - continue; + { + /* Clear the condition modification flag. */ + loc->condition_changed = condition_unchanged; + continue; + } /* Permanent breakpoint should always be inserted. */ if (b->enable_state == bp_permanent && ! loc->inserted) @@ -10677,6 +12634,13 @@ update_global_location_list (int should_insert) { *loc_first_p = loc; loc->duplicate = 0; + + if (is_breakpoint (loc->owner) && loc->condition_changed) + { + loc->needs_update = 1; + /* Clear the condition modification flag. */ + loc->condition_changed = condition_unchanged; + } continue; } @@ -10688,6 +12652,9 @@ update_global_location_list (int should_insert) swap_insertion (loc, *loc_first_p); loc->duplicate = 1; + /* Clear the condition modification flag. */ + loc->condition_changed = condition_unchanged; + if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted && b->enable_state != bp_permanent) internal_error (__FILE__, __LINE__, @@ -10695,10 +12662,21 @@ update_global_location_list (int should_insert) "a permanent breakpoint")); } - if (breakpoints_always_inserted_mode () && should_insert + if (breakpoints_always_inserted_mode () && (have_live_inferiors () - || (gdbarch_has_global_breakpoints (target_gdbarch)))) - insert_breakpoint_locations (); + || (gdbarch_has_global_breakpoints (target_gdbarch ())))) + { + if (should_insert) + insert_breakpoint_locations (); + else + { + /* Though should_insert is false, we may need to update conditions + on the target's side if it is evaluating such conditions. We + only update conditions for locations that are marked + "needs_update". */ + update_inserted_breakpoint_locations (); + } + } if (should_insert) download_tracepoint_locations (); @@ -10724,7 +12702,7 @@ breakpoint_retire_moribund (void) static void update_global_location_list_nothrow (int inserting) { - struct gdb_exception e; + volatile struct gdb_exception e; TRY_CATCH (e, RETURN_MASK_ERROR) update_global_location_list (inserting); @@ -10775,19 +12753,20 @@ say_where (struct breakpoint *b) } else { - if (opts.addressprint || b->loc->source_file == NULL) + if (opts.addressprint || b->loc->symtab == NULL) { printf_filtered (" at "); fputs_filtered (paddress (b->loc->gdbarch, b->loc->address), gdb_stdout); } - if (b->loc->source_file) + if (b->loc->symtab != NULL) { /* If there is a single location, we can print the location more nicely. */ if (b->loc->next == NULL) printf_filtered (": file %s, line %d.", - b->loc->source_file, b->loc->line_number); + symtab_to_filename_for_display (b->loc->symtab), + b->loc->line_number); else /* This is not ideal, but each location may have a different file name, and this at least reflects the @@ -10812,8 +12791,9 @@ static void bp_location_dtor (struct bp_location *self) { xfree (self->cond); + if (self->cond_bytecode) + free_agent_expr (self->cond_bytecode); xfree (self->function_name); - xfree (self->source_file); } static const struct bp_location_ops bp_location_ops = @@ -10868,7 +12848,8 @@ base_breakpoint_remove_location (struct bp_location *bl) static int base_breakpoint_breakpoint_hit (const struct bp_location *bl, struct address_space *aspace, - CORE_ADDR bp_addr) + CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { internal_error_pure_virtual_called (); } @@ -10922,7 +12903,57 @@ base_breakpoint_print_recreate (struct breakpoint *b, struct ui_file *fp) internal_error_pure_virtual_called (); } -static struct breakpoint_ops base_breakpoint_ops = +static void +base_breakpoint_create_sals_from_address (char **arg, + struct linespec_result *canonical, + enum bptype type_wanted, + char *addr_start, + char **copy_arg) +{ + internal_error_pure_virtual_called (); +} + +static void +base_breakpoint_create_breakpoints_sal (struct gdbarch *gdbarch, + struct linespec_result *c, + struct linespec_sals *lsal, + char *cond_string, + char *extra_string, + enum bptype type_wanted, + enum bpdisp disposition, + int thread, + int task, int ignore_count, + const struct breakpoint_ops *o, + int from_tty, int enabled, + int internal, unsigned flags) +{ + internal_error_pure_virtual_called (); +} + +static void +base_breakpoint_decode_linespec (struct breakpoint *b, char **s, + struct symtabs_and_lines *sals) +{ + internal_error_pure_virtual_called (); +} + +/* The default 'explains_signal' method. */ + +static enum bpstat_signal_value +base_breakpoint_explains_signal (struct breakpoint *b, enum gdb_signal sig) +{ + return BPSTAT_SIGNAL_HIDE; +} + +/* The default "after_condition_true" method. */ + +static void +base_breakpoint_after_condition_true (struct bpstats *bs) +{ + /* Nothing to do. */ +} + +struct breakpoint_ops base_breakpoint_ops = { base_breakpoint_dtor, base_breakpoint_allocate_location, @@ -10937,7 +12968,12 @@ static struct breakpoint_ops base_breakpoint_ops = NULL, base_breakpoint_print_one_detail, base_breakpoint_print_mention, - base_breakpoint_print_recreate + base_breakpoint_print_recreate, + base_breakpoint_create_sals_from_address, + base_breakpoint_create_breakpoints_sal, + base_breakpoint_decode_linespec, + base_breakpoint_explains_signal, + base_breakpoint_after_condition_true, }; /* Default breakpoint_ops methods. */ @@ -10978,10 +13014,15 @@ bkpt_remove_location (struct bp_location *bl) static int bkpt_breakpoint_hit (const struct bp_location *bl, - struct address_space *aspace, CORE_ADDR bp_addr) + struct address_space *aspace, CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { struct breakpoint *b = bl->owner; + if (ws->kind != TARGET_WAITKIND_STOPPED + || ws->value.sig != GDB_SIGNAL_TRAP) + return 0; + if (!breakpoint_address_match (bl->pspace->aspace, bl->address, aspace, bp_addr)) return 0; @@ -11058,6 +13099,9 @@ bkpt_print_mention (struct breakpoint *b) case bp_hardware_breakpoint: printf_filtered (_("Hardware assisted breakpoint %d"), b->number); break; + case bp_dprintf: + printf_filtered (_("Dprintf %d"), b->number); + break; } say_where (b); @@ -11083,6 +13127,45 @@ bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp) print_recreate_thread (tp, fp); } +static void +bkpt_create_sals_from_address (char **arg, + struct linespec_result *canonical, + enum bptype type_wanted, + char *addr_start, char **copy_arg) +{ + create_sals_from_address_default (arg, canonical, type_wanted, + addr_start, copy_arg); +} + +static void +bkpt_create_breakpoints_sal (struct gdbarch *gdbarch, + struct linespec_result *canonical, + struct linespec_sals *lsal, + char *cond_string, + char *extra_string, + enum bptype type_wanted, + enum bpdisp disposition, + int thread, + int task, int ignore_count, + const struct breakpoint_ops *ops, + int from_tty, int enabled, + int internal, unsigned flags) +{ + create_breakpoints_sal_default (gdbarch, canonical, lsal, + cond_string, extra_string, + type_wanted, + disposition, thread, task, + ignore_count, ops, from_tty, + enabled, internal, flags); +} + +static void +bkpt_decode_linespec (struct breakpoint *b, char **s, + struct symtabs_and_lines *sals) +{ + decode_linespec_default (b, s, sals); +} + /* Virtual table for internal breakpoints. */ static void @@ -11113,8 +13196,17 @@ internal_bkpt_re_set (struct breakpoint *b) static void internal_bkpt_check_status (bpstat bs) { - /* We do not stop for these. */ - bs->stop = 0; + if (bs->breakpoint_at->type == bp_shlib_event) + { + /* 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 dynamically loaded + objects (among other things). */ + bs->stop = stop_on_solib_events; + bs->print = stop_on_solib_events; + } + else + bs->stop = 0; } static enum print_stop_action @@ -11131,10 +13223,7 @@ internal_bkpt_print_it (bpstat bs) /* Did we stop because the user set the stop_on_solib_events variable? (If so, we report this as a generic, "Stopped due to shlib event" message.) */ - ui_out_text (uiout, _("Stopped due to shared library event\n")); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT)); + print_solib_event (0); break; case bp_thread_event: @@ -11217,13 +13306,80 @@ momentary_bkpt_print_it (bpstat bs) } } - return PRINT_UNKNOWN; + return PRINT_UNKNOWN; +} + +static void +momentary_bkpt_print_mention (struct breakpoint *b) +{ + /* Nothing to mention. These breakpoints are internal. */ +} + +/* Ensure INITIATING_FRAME is cleared when no such breakpoint exists. + + It gets cleared already on the removal of the first one of such placed + breakpoints. This is OK as they get all removed altogether. */ + +static void +longjmp_bkpt_dtor (struct breakpoint *self) +{ + struct thread_info *tp = find_thread_id (self->thread); + + if (tp) + tp->initiating_frame = null_frame_id; + + momentary_breakpoint_ops.dtor (self); +} + +/* Specific methods for probe breakpoints. */ + +static int +bkpt_probe_insert_location (struct bp_location *bl) +{ + int v = bkpt_insert_location (bl); + + if (v == 0) + { + /* The insertion was successful, now let's set the probe's semaphore + if needed. */ + bl->probe->pops->set_semaphore (bl->probe, bl->gdbarch); + } + + return v; +} + +static int +bkpt_probe_remove_location (struct bp_location *bl) +{ + /* Let's clear the semaphore before removing the location. */ + bl->probe->pops->clear_semaphore (bl->probe, bl->gdbarch); + + return bkpt_remove_location (bl); +} + +static void +bkpt_probe_create_sals_from_address (char **arg, + struct linespec_result *canonical, + enum bptype type_wanted, + char *addr_start, char **copy_arg) +{ + struct linespec_sals lsal; + + lsal.sals = parse_probes (arg, canonical); + + *copy_arg = xstrdup (canonical->addr_string); + lsal.canonical = xstrdup (*copy_arg); + + VEC_safe_push (linespec_sals, canonical->sals, &lsal); } static void -momentary_bkpt_print_mention (struct breakpoint *b) +bkpt_probe_decode_linespec (struct breakpoint *b, char **s, + struct symtabs_and_lines *sals) { - /* Nothing to mention. These breakpoints are internal. */ + *sals = parse_probes (s, NULL); + if (!sals->sals) + error (_("probe not found")); } /* The breakpoint_ops structure to be used in tracepoints. */ @@ -11236,7 +13392,8 @@ tracepoint_re_set (struct breakpoint *b) static int tracepoint_breakpoint_hit (const struct bp_location *bl, - struct address_space *aspace, CORE_ADDR bp_addr) + struct address_space *aspace, CORE_ADDR bp_addr, + const struct target_waitstatus *ws) { /* By definition, the inferior does not report stops at tracepoints. */ @@ -11309,8 +13466,250 @@ tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp) fprintf_unfiltered (fp, " passcount %d\n", tp->pass_count); } +static void +tracepoint_create_sals_from_address (char **arg, + struct linespec_result *canonical, + enum bptype type_wanted, + char *addr_start, char **copy_arg) +{ + create_sals_from_address_default (arg, canonical, type_wanted, + addr_start, copy_arg); +} + +static void +tracepoint_create_breakpoints_sal (struct gdbarch *gdbarch, + struct linespec_result *canonical, + struct linespec_sals *lsal, + char *cond_string, + char *extra_string, + enum bptype type_wanted, + enum bpdisp disposition, + int thread, + int task, int ignore_count, + const struct breakpoint_ops *ops, + int from_tty, int enabled, + int internal, unsigned flags) +{ + create_breakpoints_sal_default (gdbarch, canonical, lsal, + cond_string, extra_string, + type_wanted, + disposition, thread, task, + ignore_count, ops, from_tty, + enabled, internal, flags); +} + +static void +tracepoint_decode_linespec (struct breakpoint *b, char **s, + struct symtabs_and_lines *sals) +{ + decode_linespec_default (b, s, sals); +} + struct breakpoint_ops tracepoint_breakpoint_ops; +/* The breakpoint_ops structure to be use on tracepoints placed in a + static probe. */ + +static void +tracepoint_probe_create_sals_from_address (char **arg, + struct linespec_result *canonical, + enum bptype type_wanted, + char *addr_start, char **copy_arg) +{ + /* We use the same method for breakpoint on probes. */ + bkpt_probe_create_sals_from_address (arg, canonical, type_wanted, + addr_start, copy_arg); +} + +static void +tracepoint_probe_decode_linespec (struct breakpoint *b, char **s, + struct symtabs_and_lines *sals) +{ + /* We use the same method for breakpoint on probes. */ + bkpt_probe_decode_linespec (b, s, sals); +} + +static struct breakpoint_ops tracepoint_probe_breakpoint_ops; + +/* Dprintf breakpoint_ops methods. */ + +static void +dprintf_re_set (struct breakpoint *b) +{ + breakpoint_re_set_default (b); + + /* This breakpoint could have been pending, and be resolved now, and + if so, we should now have the extra string. If we don't, the + dprintf was malformed when created, but we couldn't tell because + we can't extract the extra string until the location is + resolved. */ + if (b->loc != NULL && b->extra_string == NULL) + error (_("Format string required")); + + /* 1 - connect to target 1, that can run breakpoint commands. + 2 - create a dprintf, which resolves fine. + 3 - disconnect from target 1 + 4 - connect to target 2, that can NOT run breakpoint commands. + + After steps #3/#4, you'll want the dprintf command list to + be updated, because target 1 and 2 may well return different + answers for target_can_run_breakpoint_commands(). + Given absence of finer grained resetting, we get to do + it all the time. */ + if (b->extra_string != NULL) + update_dprintf_command_list (b); +} + +/* Implement the "print_recreate" breakpoint_ops method for dprintf. */ + +static void +dprintf_print_recreate (struct breakpoint *tp, struct ui_file *fp) +{ + fprintf_unfiltered (fp, "dprintf %s%s", tp->addr_string, + tp->extra_string); + print_recreate_thread (tp, fp); +} + +/* Implement the "after_condition_true" breakpoint_ops method for + dprintf. + + dprintf's are implemented with regular commands in their command + list, but we run the commands here instead of before presenting the + stop to the user, as dprintf's don't actually cause a stop. This + also makes it so that the commands of multiple dprintfs at the same + address are all handled. */ + +static void +dprintf_after_condition_true (struct bpstats *bs) +{ + struct cleanup *old_chain; + struct bpstats tmp_bs = { NULL }; + struct bpstats *tmp_bs_p = &tmp_bs; + + /* dprintf's never cause a stop. This wasn't set in the + check_status hook instead because that would make the dprintf's + condition not be evaluated. */ + bs->stop = 0; + + /* Run the command list here. Take ownership of it instead of + copying. We never want these commands to run later in + bpstat_do_actions, if a breakpoint that causes a stop happens to + be set at same address as this dprintf, or even if running the + commands here throws. */ + tmp_bs.commands = bs->commands; + bs->commands = NULL; + old_chain = make_cleanup_decref_counted_command_line (&tmp_bs.commands); + + bpstat_do_actions_1 (&tmp_bs_p); + + /* 'tmp_bs.commands' will usually be NULL by now, but + bpstat_do_actions_1 may return early without processing the whole + list. */ + do_cleanups (old_chain); +} + +/* The breakpoint_ops structure to be used on static tracepoints with + markers (`-m'). */ + +static void +strace_marker_create_sals_from_address (char **arg, + struct linespec_result *canonical, + enum bptype type_wanted, + char *addr_start, char **copy_arg) +{ + struct linespec_sals lsal; + + lsal.sals = decode_static_tracepoint_spec (arg); + + *copy_arg = savestring (addr_start, *arg - addr_start); + + canonical->addr_string = xstrdup (*copy_arg); + lsal.canonical = xstrdup (*copy_arg); + VEC_safe_push (linespec_sals, canonical->sals, &lsal); +} + +static void +strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch, + struct linespec_result *canonical, + struct linespec_sals *lsal, + char *cond_string, + char *extra_string, + enum bptype type_wanted, + enum bpdisp disposition, + int thread, + int task, int ignore_count, + const struct breakpoint_ops *ops, + int from_tty, int enabled, + int internal, unsigned flags) +{ + int i; + + /* If the user is creating a static tracepoint by marker id + (strace -m MARKER_ID), then store the sals index, so that + breakpoint_re_set can try to match up which of the newly + found markers corresponds to this one, and, don't try to + expand multiple locations for each sal, given than SALS + already should contain all sals for MARKER_ID. */ + + for (i = 0; i < lsal->sals.nelts; ++i) + { + struct symtabs_and_lines expanded; + struct tracepoint *tp; + struct cleanup *old_chain; + char *addr_string; + + expanded.nelts = 1; + expanded.sals = &lsal->sals.sals[i]; + + addr_string = xstrdup (canonical->addr_string); + old_chain = make_cleanup (xfree, addr_string); + + tp = XCNEW (struct tracepoint); + init_breakpoint_sal (&tp->base, gdbarch, expanded, + addr_string, NULL, + cond_string, extra_string, + type_wanted, disposition, + thread, task, ignore_count, ops, + from_tty, enabled, internal, flags, + canonical->special_display); + /* Given that its possible to have multiple markers with + the same string id, if the user is creating a static + tracepoint by marker id ("strace -m MARKER_ID"), then + store the sals index, so that breakpoint_re_set can + try to match up which of the newly found markers + corresponds to this one */ + tp->static_trace_marker_id_idx = i; + + install_breakpoint (internal, &tp->base, 0); + + discard_cleanups (old_chain); + } +} + +static void +strace_marker_decode_linespec (struct breakpoint *b, char **s, + struct symtabs_and_lines *sals) +{ + struct tracepoint *tp = (struct tracepoint *) b; + + *sals = decode_static_tracepoint_spec (s); + if (sals->nelts > tp->static_trace_marker_id_idx) + { + sals->sals[0] = sals->sals[tp->static_trace_marker_id_idx]; + sals->nelts = 1; + } + else + error (_("marker %s not found"), tp->static_trace_marker_id); +} + +static struct breakpoint_ops strace_marker_breakpoint_ops; + +static int +strace_marker_p (struct breakpoint *b) +{ + return b->ops == &strace_marker_breakpoint_ops; +} + /* Delete a breakpoint and clean up all traces of it in the data structures. */ @@ -11592,7 +13991,6 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal) struct tracepoint *tp = (struct tracepoint *) b; struct static_tracepoint_marker marker; CORE_ADDR pc; - int i; pc = sal.pc; if (sal.line) @@ -11653,31 +14051,26 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal) SYMBOL_PRINT_NAME (sym)); ui_out_text (uiout, " at "); } - ui_out_field_string (uiout, "file", sal2.symtab->filename); + ui_out_field_string (uiout, "file", + symtab_to_filename_for_display (sal2.symtab)); ui_out_text (uiout, ":"); if (ui_out_is_mi_like_p (uiout)) { - char *fullname = symtab_to_fullname (sal2.symtab); + const char *fullname = symtab_to_fullname (sal2.symtab); - if (fullname) - ui_out_field_string (uiout, "fullname", fullname); + ui_out_field_string (uiout, "fullname", fullname); } ui_out_field_int (uiout, "line", sal2.line); ui_out_text (uiout, "\n"); b->loc->line_number = sal2.line; - - xfree (b->loc->source_file); - if (sym) - b->loc->source_file = xstrdup (sal2.symtab->filename); - else - b->loc->source_file = NULL; + b->loc->symtab = sym != NULL ? sal2.symtab : NULL; xfree (b->addr_string); b->addr_string = xstrprintf ("%s:%d", - sal2.symtab->filename, + symtab_to_filename_for_display (sal2.symtab), b->loc->line_number); /* Might be nice to check if function changed, and warn if @@ -11763,13 +14156,14 @@ update_breakpoint_locations (struct breakpoint *b, old symtab. */ if (b->cond_string != NULL) { - char *s; - struct gdb_exception e; + const char *s; + volatile struct gdb_exception e; s = b->cond_string; TRY_CATCH (e, RETURN_MASK_ERROR) { - new_loc->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), + new_loc->cond = parse_exp_1 (&s, sals.sals[i].pc, + block_for_pc (sals.sals[i].pc), 0); } if (e.reason < 0) @@ -11845,54 +14239,15 @@ static struct symtabs_and_lines addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found) { char *s; - int marker_spec; struct symtabs_and_lines sals = {0}; volatile struct gdb_exception e; + gdb_assert (b->ops != NULL); s = addr_string; - marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s); TRY_CATCH (e, RETURN_MASK_ERROR) { - if (marker_spec) - { - struct tracepoint *tp = (struct tracepoint *) b; - - sals = decode_static_tracepoint_spec (&s); - if (sals.nelts > tp->static_trace_marker_id_idx) - { - sals.sals[0] = sals.sals[tp->static_trace_marker_id_idx]; - sals.nelts = 1; - } - else - error (_("marker %s not found"), tp->static_trace_marker_id); - } - else - { - struct linespec_result canonical; - - init_linespec_result (&canonical); - decode_line_full (&s, DECODE_LINE_FUNFIRSTLINE, - (struct symtab *) NULL, 0, - &canonical, multiple_symbols_all, - b->filter); - - /* We should get 0 or 1 resulting SALs. */ - gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2); - - if (VEC_length (linespec_sals, canonical.sals) > 0) - { - struct linespec_sals *lsal; - - lsal = VEC_index (linespec_sals, canonical.sals, 0); - sals = lsal->sals; - /* Arrange it so the destructor does not free the - contents. */ - lsal->sals.sals = NULL; - } - - destroy_linespec_result (&canonical); - } + b->ops->decode_linespec (b, &s, &sals); } if (e.reason < 0) { @@ -11932,20 +14287,22 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found) resolve_sal_pc (&sals.sals[i]); if (b->condition_not_parsed && s && s[0]) { - char *cond_string = 0; - int thread = -1; - int task = 0; + char *cond_string, *extra_string; + int thread, task; find_condition_and_thread (s, sals.sals[0].pc, - &cond_string, &thread, &task); + &cond_string, &thread, &task, + &extra_string); if (cond_string) b->cond_string = cond_string; b->thread = thread; b->task = task; + if (extra_string) + b->extra_string = extra_string; b->condition_not_parsed = 0; } - if (b->type == bp_static_tracepoint && !marker_spec) + if (b->type == bp_static_tracepoint && !strace_marker_p (b)) sals.sals[0] = update_static_tracepoint (b, sals.sals[0]); *found = 1; @@ -11988,6 +14345,75 @@ breakpoint_re_set_default (struct breakpoint *b) update_breakpoint_locations (b, expanded, expanded_end); } +/* Default method for creating SALs from an address string. It basically + calls parse_breakpoint_sals. Return 1 for success, zero for failure. */ + +static void +create_sals_from_address_default (char **arg, + struct linespec_result *canonical, + enum bptype type_wanted, + char *addr_start, char **copy_arg) +{ + parse_breakpoint_sals (arg, canonical); +} + +/* Call create_breakpoints_sal for the given arguments. This is the default + function for the `create_breakpoints_sal' method of + breakpoint_ops. */ + +static void +create_breakpoints_sal_default (struct gdbarch *gdbarch, + struct linespec_result *canonical, + struct linespec_sals *lsal, + char *cond_string, + char *extra_string, + enum bptype type_wanted, + enum bpdisp disposition, + int thread, + int task, int ignore_count, + const struct breakpoint_ops *ops, + int from_tty, int enabled, + int internal, unsigned flags) +{ + create_breakpoints_sal (gdbarch, canonical, cond_string, + extra_string, + type_wanted, disposition, + thread, task, ignore_count, ops, from_tty, + enabled, internal, flags); +} + +/* Decode the line represented by S by calling decode_line_full. This is the + default function for the `decode_linespec' method of breakpoint_ops. */ + +static void +decode_linespec_default (struct breakpoint *b, char **s, + struct symtabs_and_lines *sals) +{ + struct linespec_result canonical; + + init_linespec_result (&canonical); + decode_line_full (s, DECODE_LINE_FUNFIRSTLINE, + (struct symtab *) NULL, 0, + &canonical, multiple_symbols_all, + b->filter); + + /* We should get 0 or 1 resulting SALs. */ + gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2); + + if (VEC_length (linespec_sals, canonical.sals) > 0) + { + struct linespec_sals *lsal; + + lsal = VEC_index (linespec_sals, canonical.sals, 0); + *sals = lsal->sals; + /* Arrange it so the destructor does not free the + contents. */ + lsal->sals.sals = NULL; + } + + destroy_linespec_result (&canonical); +} + /* Prepare the global context for a re-set of breakpoint B. */ static struct cleanup * @@ -12054,9 +14480,6 @@ breakpoint_re_set (void) create_longjmp_master_breakpoint (); create_std_terminate_master_breakpoint (); create_exception_master_breakpoint (); - - /* While we're at it, reset the skip list too. */ - skip_re_set (); } /* Reset the thread number of this breakpoint: @@ -12117,7 +14540,6 @@ set_ignore_count (int bptnum, int count, int from_tty) "crossings of breakpoint %d."), count, bptnum); } - breakpoints_changed (); observer_notify_breakpoint_modified (b); return; } @@ -12254,6 +14676,9 @@ disable_breakpoint (struct breakpoint *bpt) bpt->enable_state = bp_disabled; + /* Mark breakpoint locations modified. */ + mark_breakpoint_modified (bpt); + if (target_supports_enable_disable_tracepoint () && current_trace_status ()->running && is_tracepoint (bpt)) { @@ -12301,7 +14726,11 @@ disable_command (char *args, int from_tty) struct bp_location *loc = find_location_by_number (args); if (loc) { - loc->enabled = 0; + if (loc->enabled) + { + loc->enabled = 0; + mark_breakpoint_location_modified (loc); + } if (target_supports_enable_disable_tracepoint () && current_trace_status ()->running && loc->owner && is_tracepoint (loc->owner)) @@ -12314,7 +14743,8 @@ disable_command (char *args, int from_tty) } static void -enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition) +enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition, + int count) { int target_resources_ok; @@ -12335,7 +14765,7 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition) { /* Initialize it just to avoid a GCC false warning. */ enum enable_state orig_enable_state = 0; - struct gdb_exception e; + volatile struct gdb_exception e; TRY_CATCH (e, RETURN_MASK_ALL) { @@ -12357,6 +14787,11 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition) if (bpt->enable_state != bp_permanent) bpt->enable_state = bp_enabled; + bpt->enable_state = bp_enabled; + + /* Mark breakpoint locations modified. */ + mark_breakpoint_modified (bpt); + if (target_supports_enable_disable_tracepoint () && current_trace_status ()->running && is_tracepoint (bpt)) { @@ -12367,9 +14802,9 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition) } bpt->disposition = disposition; + bpt->enable_count = count; update_global_location_list (1); - breakpoints_changed (); - + observer_notify_breakpoint_modified (bpt); } @@ -12377,7 +14812,7 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition) void enable_breakpoint (struct breakpoint *bpt) { - enable_breakpoint_disp (bpt, bpt->disposition); + enable_breakpoint_disp (bpt, bpt->disposition, 0); } static void @@ -12415,7 +14850,11 @@ enable_command (char *args, int from_tty) struct bp_location *loc = find_location_by_number (args); if (loc) { - loc->enabled = 1; + if (!loc->enabled) + { + loc->enabled = 1; + mark_breakpoint_location_modified (loc); + } if (target_supports_enable_disable_tracepoint () && current_trace_status ()->running && loc->owner && is_tracepoint (loc->owner)) @@ -12427,18 +14866,27 @@ enable_command (char *args, int from_tty) map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL); } +/* This struct packages up disposition data for application to multiple + breakpoints. */ + +struct disp_data +{ + enum bpdisp disp; + int count; +}; + static void do_enable_breakpoint_disp (struct breakpoint *bpt, void *arg) { - enum bpdisp disp = *(enum bpdisp *) arg; + struct disp_data disp_data = *(struct disp_data *) arg; - enable_breakpoint_disp (bpt, disp); + enable_breakpoint_disp (bpt, disp_data.disp, disp_data.count); } static void do_map_enable_once_breakpoint (struct breakpoint *bpt, void *ignore) { - enum bpdisp disp = disp_disable; + struct disp_data disp = { disp_disable, 1 }; iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp); } @@ -12449,10 +14897,26 @@ enable_once_command (char *args, int from_tty) map_breakpoint_numbers (args, do_map_enable_once_breakpoint, NULL); } +static void +do_map_enable_count_breakpoint (struct breakpoint *bpt, void *countptr) +{ + struct disp_data disp = { disp_disable, *(int *) countptr }; + + iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp); +} + +static void +enable_count_command (char *args, int from_tty) +{ + int count = get_number (&args); + + map_breakpoint_numbers (args, do_map_enable_count_breakpoint, &count); +} + static void do_map_enable_delete_breakpoint (struct breakpoint *bpt, void *ignore) { - enum bpdisp disp = disp_del; + struct disp_data disp = { disp_del, 1 }; iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp); } @@ -12478,7 +14942,8 @@ show_breakpoint_cmd (char *args, int from_tty) GDB itself. */ static void -invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len, +invalidate_bp_value_on_memory_change (struct inferior *inferior, + CORE_ADDR addr, ssize_t len, const bfd_byte *data) { struct breakpoint *bp; @@ -12506,27 +14971,6 @@ invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len, } } -/* Use the last displayed codepoint's values, or nothing - if they aren't valid. */ - -struct symtabs_and_lines -decode_line_spec_1 (char *string, int flags) -{ - struct symtabs_and_lines sals; - - if (string == 0) - error (_("Empty line specification.")); - if (last_displayed_sal_is_valid ()) - sals = decode_line_1 (&string, flags, - get_last_displayed_symtab (), - get_last_displayed_line ()); - else - sals = decode_line_1 (&string, flags, (struct symtab *) NULL, 0); - if (*string) - error (_("Junk at end of line specification: %s"), string); - return sals; -} - /* Create and insert a raw software breakpoint at PC. Return an identifier, which should be used to remove the breakpoint later. In general, places which call this should be using something on the @@ -12713,9 +15157,10 @@ is_syscall_catchpoint_enabled (struct breakpoint *bp) int catch_syscall_enabled (void) { - struct inferior *inf = current_inferior (); + struct catch_syscall_inferior_data *inf_data + = get_catch_syscall_inferior_data (current_inferior ()); - return inf->total_syscalls_count != 0; + return inf_data->total_syscalls_count != 0; } int @@ -12745,13 +15190,13 @@ catching_syscall_number (int syscall_number) } /* Complete syscall names. Used by "catch syscall". */ -static char ** +static VEC (char_ptr) * catch_syscall_completer (struct cmd_list_element *cmd, char *text, char *word) { const char **list = get_syscall_names (); - char **retlist - = (list == NULL) ? NULL : complete_on_enum (list, text, word); + VEC (char_ptr) *retlist + = (list == NULL) ? NULL : complete_on_enum (list, word, word); xfree (list); return retlist; @@ -12767,57 +15212,71 @@ set_tracepoint_count (int num) set_internalvar_integer (lookup_internalvar ("tpnum"), num); } -void +static void trace_command (char *arg, int from_tty) { - if (create_breakpoint (get_current_arch (), - arg, - NULL, 0, 1 /* parse arg */, - 0 /* tempflag */, - bp_tracepoint /* type_wanted */, - 0 /* Ignore count */, - pending_break_support, - &tracepoint_breakpoint_ops, - from_tty, - 1 /* enabled */, - 0 /* internal */, 0)) - set_tracepoint_count (breakpoint_count); + struct breakpoint_ops *ops; + const char *arg_cp = arg; + + if (arg && probe_linespec_to_ops (&arg_cp)) + ops = &tracepoint_probe_breakpoint_ops; + else + ops = &tracepoint_breakpoint_ops; + + create_breakpoint (get_current_arch (), + arg, + NULL, 0, NULL, 1 /* parse arg */, + 0 /* tempflag */, + bp_tracepoint /* type_wanted */, + 0 /* Ignore count */, + pending_break_support, + ops, + from_tty, + 1 /* enabled */, + 0 /* internal */, 0); } -void +static void ftrace_command (char *arg, int from_tty) { - if (create_breakpoint (get_current_arch (), - arg, - NULL, 0, 1 /* parse arg */, - 0 /* tempflag */, - bp_fast_tracepoint /* type_wanted */, - 0 /* Ignore count */, - pending_break_support, - &tracepoint_breakpoint_ops, - from_tty, - 1 /* enabled */, - 0 /* internal */, 0)) - set_tracepoint_count (breakpoint_count); + create_breakpoint (get_current_arch (), + arg, + NULL, 0, NULL, 1 /* parse arg */, + 0 /* tempflag */, + bp_fast_tracepoint /* type_wanted */, + 0 /* Ignore count */, + pending_break_support, + &tracepoint_breakpoint_ops, + from_tty, + 1 /* enabled */, + 0 /* internal */, 0); } /* strace command implementation. Creates a static tracepoint. */ -void +static void strace_command (char *arg, int from_tty) { - if (create_breakpoint (get_current_arch (), - arg, - NULL, 0, 1 /* parse arg */, - 0 /* tempflag */, - bp_static_tracepoint /* type_wanted */, - 0 /* Ignore count */, - pending_break_support, - &tracepoint_breakpoint_ops, - from_tty, - 1 /* enabled */, - 0 /* internal */, 0)) - set_tracepoint_count (breakpoint_count); + struct breakpoint_ops *ops; + + /* Decide if we are dealing with a static tracepoint marker (`-m'), + or with a normal static tracepoint. */ + if (arg && strncmp (arg, "-m", 2) == 0 && isspace (arg[2])) + ops = &strace_marker_breakpoint_ops; + else + ops = &tracepoint_breakpoint_ops; + + create_breakpoint (get_current_arch (), + arg, + NULL, 0, NULL, 1 /* parse arg */, + 0 /* tempflag */, + bp_static_tracepoint /* type_wanted */, + 0 /* Ignore count */, + pending_break_support, + ops, + from_tty, + 1 /* enabled */, + 0 /* internal */, 0); } /* Set up a fake reader function that gets command lines from a linked @@ -12861,7 +15320,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp) warning (_("Uploaded tracepoint %d has no " "source location, using raw address"), utp->number); - sprintf (small_buf, "*%s", hex_string (utp->addr)); + xsnprintf (small_buf, sizeof (small_buf), "*%s", hex_string (utp->addr)); addr_str = small_buf; } @@ -12873,7 +15332,8 @@ create_tracepoint_from_upload (struct uploaded_tp *utp) if (!create_breakpoint (get_current_arch (), addr_str, - utp->cond_string, -1, 0 /* parse cond/thread */, + utp->cond_string, -1, NULL, + 0 /* parse cond/thread */, 0 /* tempflag */, utp->type /* type_wanted */, 0 /* Ignore count */, @@ -12885,15 +15345,14 @@ create_tracepoint_from_upload (struct uploaded_tp *utp) CREATE_BREAKPOINT_FLAGS_INSERTED)) return NULL; - set_tracepoint_count (breakpoint_count); - /* Get the tracepoint we just created. */ tp = get_tracepoint (tracepoint_count); gdb_assert (tp != NULL); if (utp->pass > 0) { - sprintf (small_buf, "%d %d", utp->pass, tp->base.number); + xsnprintf (small_buf, sizeof (small_buf), "%d %d", utp->pass, + tp->base.number); trace_pass_command (small_buf, 0); } @@ -13006,7 +15465,7 @@ static void trace_pass_set_count (struct tracepoint *tp, int count, int from_tty) { tp->pass_count = count; - observer_notify_tracepoint_modified (tp->base.number); + observer_notify_breakpoint_modified (&tp->base); if (from_tty) printf_filtered (_("Setting tracepoint %d's passcount to %d\n"), tp->base.number, count); @@ -13030,9 +15489,7 @@ trace_pass_command (char *args, int from_tty) count = strtoul (args, &args, 10); /* Count comes first, then TP num. */ - while (*args && isspace ((int) *args)) - args++; - + args = skip_spaces (args); if (*args && strncasecmp (args, "all", 3) == 0) { struct breakpoint *b; @@ -13108,7 +15565,6 @@ get_tracepoint_by_number (char **arg, struct get_number_or_range_state *state, int optional_p) { - extern int tracepoint_count; struct breakpoint *t; int tpnum; char *instring = arg == NULL ? NULL : *arg; @@ -13241,7 +15697,7 @@ save_breakpoints (char *filename, int from_tty, if (tp->ignore_count) fprintf_unfiltered (fp, " ignore $bpnum %d\n", tp->ignore_count); - if (tp->commands) + if (tp->type != bp_dprintf && tp->commands) { volatile struct gdb_exception ex; @@ -13323,7 +15779,10 @@ all_tracepoints (void) COMMAND should be a string constant containing the name of the command. */ #define BREAK_ARGS_HELP(command) \ -command" [LOCATION] [thread THREADNUM] [if CONDITION]\n\ +command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\ +PROBE_MODIFIER shall be present if the command is to be placed in a\n\ +probe point. Accepted values are `-probe' (for a generic, automatically\n\ +guessed probe type) or `-probe-stap' (for a SystemTap probe).\n\ LOCATION may be a line number, function name, or \"*\" and an address.\n\ If a line number is specified, break at start of code for that line.\n\ If a function is specified, break at start of code for that function.\n\ @@ -13349,8 +15808,7 @@ void add_catch_command (char *name, char *docstring, void (*sfunc) (char *args, int from_tty, struct cmd_list_element *command), - char **(*completer) (struct cmd_list_element *cmd, - char *text, char *word), + completer_ftype *completer, void *user_data_catch, void *user_data_tcatch) { @@ -13372,9 +15830,12 @@ add_catch_command (char *name, char *docstring, static void clear_syscall_counts (struct inferior *inf) { - inf->total_syscalls_count = 0; - inf->any_syscall_count = 0; - VEC_free (int, inf->syscalls_counts); + struct catch_syscall_inferior_data *inf_data + = get_catch_syscall_inferior_data (inf); + + inf_data->total_syscalls_count = 0; + inf_data->any_syscall_count = 0; + VEC_free (int, inf_data->syscalls_counts); } static void @@ -13418,7 +15879,8 @@ is_non_inline_function (struct breakpoint *b) have been inlined. */ int -pc_at_non_inline_function (struct address_space *aspace, CORE_ADDR pc) +pc_at_non_inline_function (struct address_space *aspace, CORE_ADDR pc, + const struct target_waitstatus *ws) { struct breakpoint *b; struct bp_location *bl; @@ -13431,7 +15893,7 @@ pc_at_non_inline_function (struct address_space *aspace, CORE_ADDR pc) for (bl = b->loc; bl != NULL; bl = bl->next) { if (!bl->shlib_disabled - && bpstat_check_location (bl, aspace, pc)) + && bpstat_check_location (bl, aspace, pc, ws)) return 1; } } @@ -13439,6 +15901,18 @@ pc_at_non_inline_function (struct address_space *aspace, CORE_ADDR pc) return 0; } +/* Remove any references to OBJFILE which is going to be freed. */ + +void +breakpoint_free_objfile (struct objfile *objfile) +{ + struct bp_location **locp, *loc; + + ALL_BP_LOCATIONS (loc, locp) + if (loc->symtab != NULL && loc->symtab->objfile == objfile) + loc->symtab = NULL; +} + void initialize_breakpoint_ops (void) { @@ -13459,6 +15933,9 @@ initialize_breakpoint_ops (void) ops->insert_location = bkpt_insert_location; ops->remove_location = bkpt_remove_location; ops->breakpoint_hit = bkpt_breakpoint_hit; + ops->create_sals_from_address = bkpt_create_sals_from_address; + ops->create_breakpoints_sal = bkpt_create_breakpoints_sal; + ops->decode_linespec = bkpt_decode_linespec; /* The breakpoint_ops structure to be used in regular breakpoints. */ ops = &bkpt_breakpoint_ops; @@ -13496,6 +15973,19 @@ initialize_breakpoint_ops (void) ops->print_it = momentary_bkpt_print_it; ops->print_mention = momentary_bkpt_print_mention; + /* Momentary breakpoints for bp_longjmp and bp_exception. */ + ops = &longjmp_breakpoint_ops; + *ops = momentary_breakpoint_ops; + ops->dtor = longjmp_bkpt_dtor; + + /* Probe breakpoints. */ + ops = &bkpt_probe_breakpoint_ops; + *ops = bkpt_breakpoint_ops; + ops->insert_location = bkpt_probe_insert_location; + ops->remove_location = bkpt_probe_remove_location; + ops->create_sals_from_address = bkpt_probe_create_sals_from_address; + ops->decode_linespec = bkpt_probe_decode_linespec; + /* GNU v3 exception catchpoints. */ ops = &gnu_v3_exception_catchpoint_ops; *ops = bkpt_breakpoint_ops; @@ -13518,6 +16008,7 @@ initialize_breakpoint_ops (void) ops->print_it = print_it_watchpoint; ops->print_mention = print_mention_watchpoint; ops->print_recreate = print_recreate_watchpoint; + ops->explains_signal = explains_signal_watchpoint; /* Masked watchpoints. */ ops = &masked_watchpoint_breakpoint_ops; @@ -13539,6 +16030,22 @@ initialize_breakpoint_ops (void) ops->print_one_detail = tracepoint_print_one_detail; ops->print_mention = tracepoint_print_mention; ops->print_recreate = tracepoint_print_recreate; + ops->create_sals_from_address = tracepoint_create_sals_from_address; + ops->create_breakpoints_sal = tracepoint_create_breakpoints_sal; + ops->decode_linespec = tracepoint_decode_linespec; + + /* Probe tracepoints. */ + ops = &tracepoint_probe_breakpoint_ops; + *ops = tracepoint_breakpoint_ops; + ops->create_sals_from_address = tracepoint_probe_create_sals_from_address; + ops->decode_linespec = tracepoint_probe_decode_linespec; + + /* Static tracepoints with marker (`-m'). */ + ops = &strace_marker_breakpoint_ops; + *ops = tracepoint_breakpoint_ops; + ops->create_sals_from_address = strace_marker_create_sals_from_address; + ops->create_breakpoints_sal = strace_marker_create_breakpoints_sal; + ops->decode_linespec = strace_marker_decode_linespec; /* Fork catchpoints. */ ops = &catch_fork_breakpoint_ops; @@ -13585,8 +16092,34 @@ initialize_breakpoint_ops (void) ops->print_one = print_one_catch_syscall; ops->print_mention = print_mention_catch_syscall; ops->print_recreate = print_recreate_catch_syscall; + + /* Solib-related catchpoints. */ + ops = &catch_solib_breakpoint_ops; + *ops = base_breakpoint_ops; + ops->dtor = dtor_catch_solib; + ops->insert_location = insert_catch_solib; + ops->remove_location = remove_catch_solib; + ops->breakpoint_hit = breakpoint_hit_catch_solib; + ops->check_status = check_status_catch_solib; + ops->print_it = print_it_catch_solib; + ops->print_one = print_one_catch_solib; + ops->print_mention = print_mention_catch_solib; + ops->print_recreate = print_recreate_catch_solib; + + ops = &dprintf_breakpoint_ops; + *ops = bkpt_base_breakpoint_ops; + ops->re_set = dprintf_re_set; + ops->resources_needed = bkpt_resources_needed; + ops->print_it = bkpt_print_it; + ops->print_mention = bkpt_print_mention; + ops->print_recreate = dprintf_print_recreate; + ops->after_condition_true = dprintf_after_condition_true; } +/* Chain containing all defined "enable breakpoint" subcommands. */ + +static struct cmd_list_element *enablebreaklist = NULL; + void _initialize_breakpoint (void) { @@ -13598,7 +16131,12 @@ _initialize_breakpoint (void) observer_attach_inferior_exit (clear_syscall_counts); observer_attach_memory_changed (invalidate_bp_value_on_memory_change); - breakpoint_objfile_key = register_objfile_data (); + breakpoint_objfile_key + = register_objfile_data_with_cleanup (NULL, free_breakpoint_probes); + + catch_syscall_inferior_data + = register_inferior_data_with_cleanup (NULL, + catch_syscall_inferior_data_cleanup); breakpoint_chain = 0; /* Don't bother to call set_breakpoint_count. $bpnum isn't useful @@ -13622,10 +16160,11 @@ Type a line containing \"end\" to indicate the end of them.\n\ Give \"silent\" as the first line to make the breakpoint silent;\n\ then no output is printed when it is hit, except what the commands print.")); - add_com ("condition", class_breakpoint, condition_command, _("\ + c = add_com ("condition", class_breakpoint, condition_command, _("\ Specify breakpoint number N to break only if COND is true.\n\ Usage is `condition N COND', where N is an integer and COND is an\n\ expression to be evaluated whenever breakpoint N is reached.")); + set_cmd_completer (c, condition_completer); c = add_com ("tbreak", class_breakpoint, tbreak_command, _("\ Set a temporary breakpoint.\n\ @@ -13686,6 +16225,12 @@ Enable breakpoints and delete when hit. Give breakpoint numbers.\n\ If a breakpoint is hit while enabled in this fashion, it is deleted."), &enablebreaklist); + add_cmd ("count", no_class, enable_count_command, _("\ +Enable breakpoints for COUNT hits. Give count and then breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion,\n\ +the count is decremented; when it reaches zero, the breakpoint is disabled."), + &enablebreaklist); + add_cmd ("delete", no_class, enable_delete_command, _("\ Enable breakpoints and delete when hit. Give breakpoint numbers.\n\ If a breakpoint is hit while enabled in this fashion, it is deleted."), @@ -13696,6 +16241,12 @@ Enable breakpoints for one hit. Give breakpoint numbers.\n\ If a breakpoint is hit while enabled in this fashion, it becomes disabled."), &enablelist); + add_cmd ("count", no_class, enable_count_command, _("\ +Enable breakpoints for COUNT hits. Give count and then breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion,\n\ +the count is decremented; when it reaches zero, the breakpoint is disabled."), + &enablelist); + add_prefix_cmd ("disable", class_breakpoint, disable_command, _("\ Disable some breakpoints.\n\ Arguments are breakpoint numbers with spaces in between.\n\ @@ -13862,15 +16413,13 @@ Set temporary catchpoints to catch events."), /* Add catch and tcatch sub-commands. */ add_catch_command ("catch", _("\ -Catch an exception, when caught.\n\ -With an argument, catch only exceptions with the given name."), +Catch an exception, when caught."), 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 an exception, when thrown."), catch_throw_command, NULL, CATCH_PERMANENT, @@ -13890,6 +16439,20 @@ With an argument, catch only exceptions with the given name."), NULL, CATCH_PERMANENT, CATCH_TEMPORARY); + add_catch_command ("load", _("Catch loads of shared libraries.\n\ +Usage: catch load [REGEX]\n\ +If REGEX is given, only stop for libraries matching the regular expression."), + catch_load_command_1, + NULL, + CATCH_PERMANENT, + CATCH_TEMPORARY); + add_catch_command ("unload", _("Catch unloads of shared libraries.\n\ +Usage: catch unload [REGEX]\n\ +If REGEX is given, only stop for libraries matching the regular expression."), + catch_unload_command_1, + NULL, + CATCH_PERMANENT, + CATCH_TEMPORARY); add_catch_command ("syscall", _("\ Catch system calls by their names and/or numbers.\n\ Arguments say which system calls to catch. If no arguments\n\ @@ -14006,6 +16569,7 @@ Delete specified tracepoints.\n\ Arguments are tracepoint numbers, separated by spaces.\n\ No argument means delete all tracepoints."), &deletelist); + add_alias_cmd ("tr", "tracepoints", class_trace, 1, &deletelist); c = add_cmd ("tracepoints", class_trace, disable_trace_command, _("\ Disable specified tracepoints.\n\ @@ -14089,8 +16653,8 @@ a warning will be emitted for such breakpoints."), &breakpoint_set_cmdlist, &breakpoint_show_cmdlist); - add_setshow_enum_cmd ("always-inserted", class_support, - always_inserted_enums, &always_inserted_mode, _("\ + add_setshow_auto_boolean_cmd ("always-inserted", class_support, + &always_inserted_mode, _("\ Set mode for inserting breakpoints."), _("\ Show mode for inserting breakpoints."), _("\ When this mode is off, breakpoints are inserted in inferior when it is\n\ @@ -14101,8 +16665,25 @@ the behaviour depends on the non-stop setting (see help set non-stop).\n\ In this case, if gdb is controlling the inferior in non-stop mode, gdb\n\ behaves as if always-inserted mode is on; if gdb is controlling the\n\ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."), - NULL, - &show_always_inserted_mode, + NULL, + &show_always_inserted_mode, + &breakpoint_set_cmdlist, + &breakpoint_show_cmdlist); + + add_setshow_enum_cmd ("condition-evaluation", class_breakpoint, + condition_evaluation_enums, + &condition_evaluation_mode_1, _("\ +Set mode of breakpoint condition evaluation."), _("\ +Show mode of breakpoint condition evaluation."), _("\ +When this is set to \"host\", breakpoint conditions will be\n\ +evaluated on the host's side by GDB. When it is set to \"target\",\n\ +breakpoint conditions will be downloaded to the target (if the target\n\ +supports such feature) and conditions will be evaluated on the target's side.\n\ +If this is set to \"auto\" (default), this will be automatically set to\n\ +\"target\" if it supports condition evaluation, otherwise it will\n\ +be set to \"gdb\""), + &set_condition_evaluation_mode, + &show_condition_evaluation_mode, &breakpoint_set_cmdlist, &breakpoint_show_cmdlist); @@ -14122,6 +16703,58 @@ The breakpoint will stop execution of the inferior whenever it executes\n\ an instruction at any address within the [START-LOCATION, END-LOCATION]\n\ range (including START-LOCATION and END-LOCATION).")); + c = add_com ("dprintf", class_breakpoint, dprintf_command, _("\ +Set a dynamic printf at specified line or function.\n\ +dprintf location,format string,arg1,arg2,...\n\ +location may be a line number, function name, or \"*\" and an address.\n\ +If a line number is specified, break at start of code for that line.\n\ +If a function is specified, break at start of code for that function.\n\ +")); + set_cmd_completer (c, location_completer); + + add_setshow_enum_cmd ("dprintf-style", class_support, + dprintf_style_enums, &dprintf_style, _("\ +Set the style of usage for dynamic printf."), _("\ +Show the style of usage for dynamic printf."), _("\ +This setting chooses how GDB will do a dynamic printf.\n\ +If the value is \"gdb\", then the printing is done by GDB to its own\n\ +console, as with the \"printf\" command.\n\ +If the value is \"call\", the print is done by calling a function in your\n\ +program; by default printf(), but you can choose a different function or\n\ +output stream by setting dprintf-function and dprintf-channel."), + update_dprintf_commands, NULL, + &setlist, &showlist); + + dprintf_function = xstrdup ("printf"); + add_setshow_string_cmd ("dprintf-function", class_support, + &dprintf_function, _("\ +Set the function to use for dynamic printf"), _("\ +Show the function to use for dynamic printf"), NULL, + update_dprintf_commands, NULL, + &setlist, &showlist); + + dprintf_channel = xstrdup (""); + add_setshow_string_cmd ("dprintf-channel", class_support, + &dprintf_channel, _("\ +Set the channel to use for dynamic printf"), _("\ +Show the channel to use for dynamic printf"), NULL, + update_dprintf_commands, NULL, + &setlist, &showlist); + + add_setshow_boolean_cmd ("disconnected-dprintf", no_class, + &disconnected_dprintf, _("\ +Set whether dprintf continues after GDB disconnects."), _("\ +Show whether dprintf continues after GDB disconnects."), _("\ +Use this to let dprintf commands continue to hit and produce output\n\ +even if GDB disconnects or detaches from the target."), + NULL, + NULL, + &setlist, &showlist); + + add_com ("agent-printf", class_vars, agent_printf_command, _("\ +agent-printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\ +(target agent only) This is useful for formatted output in user-defined commands.")); + automatic_hardware_breakpoints = 1; observer_attach_about_to_proceed (breakpoint_about_to_proceed); diff --git a/contrib/gdb-7/gdb/breakpoint.h b/contrib/gdb-7/gdb/breakpoint.h index 3548d13a67..da79365b32 100644 --- a/contrib/gdb-7/gdb/breakpoint.h +++ b/contrib/gdb-7/gdb/breakpoint.h @@ -1,5 +1,5 @@ /* Data structures associated with breakpoints in GDB. - Copyright (C) 1992-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +22,8 @@ #include "frame.h" #include "value.h" #include "vec.h" +#include "ax.h" +#include "command.h" struct value; struct block; @@ -30,6 +32,8 @@ struct get_number_or_range_state; struct thread_info; struct bpstats; struct bp_location; +struct linespec_result; +struct linespec_sals; /* This is the maximum number of bytes a breakpoint instruction can take. Feel free to increase it. It's just used in a few places to @@ -61,6 +65,12 @@ enum bptype bp_longjmp, /* secret breakpoint to find longjmp() */ bp_longjmp_resume, /* secret breakpoint to escape longjmp() */ + /* Breakpoint placed to the same location(s) like bp_longjmp but used to + protect against stale DUMMY_FRAME. Multiple bp_longjmp_call_dummy and + one bp_call_dummy are chained together by related_breakpoint for each + DUMMY_FRAME. */ + bp_longjmp_call_dummy, + /* An internal breakpoint that is installed on the unwinder's debug hook. */ bp_exception, @@ -90,14 +100,8 @@ enum bptype 3) It can never be disabled. */ bp_watchpoint_scope, - /* The breakpoint at the end of a call dummy. */ - /* FIXME: What if the function we are calling longjmp()s out of - the call, or the user gets out with the "return" command? We - currently have no way of cleaning up the breakpoint in these - (obscure) situations. (Probably can solve this by noticing - longjmp, "return", etc., it's similar to noticing when a - watchpoint on a local variable goes out of scope (with hardware - support for watchpoints)). */ + /* The breakpoint at the end of a call dummy. See bp_longjmp_call_dummy it + is chained with by related_breakpoint. */ bp_call_dummy, /* A breakpoint set on std::terminate, that is used to catch @@ -151,6 +155,13 @@ enum bptype bp_fast_tracepoint, bp_static_tracepoint, + /* A dynamic printf stops at the given location, does a formatted + print, then automatically continues. (Although this is sort of + like a macro packaging up standard breakpoint functionality, + GDB doesn't have a way to construct types of breakpoint from + elements of behavior.) */ + bp_dprintf, + /* Event for JIT compiled code generation or deletion. */ bp_jit_event, @@ -213,6 +224,16 @@ enum target_hw_bp_type }; +/* Status of breakpoint conditions used when synchronizing + conditions with the target. */ + +enum condition_status + { + condition_unchanged = 0, + condition_modified, + condition_updated + }; + /* Information used by targets to insert and remove breakpoints. */ struct bp_target_info @@ -247,6 +268,18 @@ struct bp_target_info (e.g. if a remote stub handled the details). We may still need the size to remove the breakpoint safely. */ int placed_size; + + /* Vector of conditions the target should evaluate if it supports target-side + breakpoint conditions. */ + VEC(agent_expr_p) *conditions; + + /* Vector of commands the target should evaluate if it supports + target-side breakpoint commands. */ + VEC(agent_expr_p) *tcommands; + + /* Flag that is true if the breakpoint should be left in place even + when GDB is not connected. */ + int persist; }; /* GDB maintains two types of information about each breakpoint (or @@ -313,6 +346,33 @@ struct bp_location the owner breakpoint object. */ struct expression *cond; + /* Conditional expression in agent expression + bytecode form. This is used for stub-side breakpoint + condition evaluation. */ + struct agent_expr *cond_bytecode; + + /* Signals that the condition has changed since the last time + we updated the global location list. This means the condition + needs to be sent to the target again. This is used together + with target-side breakpoint conditions. + + condition_unchanged: It means there has been no condition changes. + + condition_modified: It means this location had its condition modified. + + condition_updated: It means we already marked all the locations that are + duplicates of this location and thus we don't need to call + force_breakpoint_reinsertion (...) for this location. */ + + enum condition_status condition_changed; + + struct agent_expr *cmd_bytecode; + + /* Signals that breakpoint conditions and/or commands need to be + re-synched with the target. This has no use other than + target-side breakpoints. */ + char needs_update; + /* This location's address is in an unloaded solib, and so this location should not be inserted. It will be automatically enabled when that solib is loaded. */ @@ -377,6 +437,15 @@ struct bp_location processor's architectual constraints. */ CORE_ADDR requested_address; + /* An additional address assigned with this location. This is currently + only used by STT_GNU_IFUNC resolver breakpoints to hold the address + of the resolver function. */ + CORE_ADDR related_address; + + /* If the location comes from a probe point, this is the probe associated + with it. */ + struct probe *probe; + char *function_name; /* Details of the placed breakpoint, when inserted. */ @@ -396,15 +465,35 @@ struct bp_location it becomes 0 this location is retired. */ int events_till_retirement; - /* Line number of this address. */ + /* Line number which was used to place this location. + + Breakpoint placed into a comment keeps it's user specified line number + despite ADDRESS resolves into a different line number. */ int line_number; - /* Source file name of this address. */ + /* Symtab which was used to place this location. This is used + to find the corresponding source file name. */ - char *source_file; + struct symtab *symtab; }; +/* Return values for bpstat_explains_signal. Note that the order of + the constants is important here; they are compared directly in + bpstat_explains_signal. */ + +enum bpstat_signal_value + { + /* bpstat does not explain this signal. */ + BPSTAT_SIGNAL_NO = 0, + + /* bpstat explains this signal; signal should not be delivered. */ + BPSTAT_SIGNAL_HIDE, + + /* bpstat explains this signal; signal should be delivered. */ + BPSTAT_SIGNAL_PASS + }; + /* This structure is a collection of function pointers that, if available, will be called instead of the performing the default action for this bptype. */ @@ -436,9 +525,14 @@ struct breakpoint_ops /* Return true if it the target has stopped due to hitting breakpoint location BL. This function does not check if we - should stop, only if BL explains the stop. */ - int (*breakpoint_hit) (const struct bp_location *bl, struct address_space *, - CORE_ADDR); + should stop, only if BL explains the stop. ASPACE is the address + space in which the event occurred, BP_ADDR is the address at + which the inferior stopped, and WS is the target_waitstatus + describing the event. */ + int (*breakpoint_hit) (const struct bp_location *bl, + struct address_space *aspace, + CORE_ADDR bp_addr, + const struct target_waitstatus *ws); /* Check internal conditions of the breakpoint referred to by BS. If we should not stop for this breakpoint, set BS->stop to 0. */ @@ -482,6 +576,49 @@ struct breakpoint_ops /* Print to FP the CLI command that recreates this breakpoint. */ void (*print_recreate) (struct breakpoint *, struct ui_file *fp); + + /* Create SALs from address string, storing the result in linespec_result. + + For an explanation about the arguments, see the function + `create_sals_from_address_default'. + + This function is called inside `create_breakpoint'. */ + void (*create_sals_from_address) (char **, struct linespec_result *, + enum bptype, char *, char **); + + /* This method will be responsible for creating a breakpoint given its SALs. + Usually, it just calls `create_breakpoints_sal' (for ordinary + breakpoints). However, there may be some special cases where we might + need to do some tweaks, e.g., see + `strace_marker_create_breakpoints_sal'. + + This function is called inside `create_breakpoint'. */ + void (*create_breakpoints_sal) (struct gdbarch *, + struct linespec_result *, + struct linespec_sals *, char *, + char *, + enum bptype, enum bpdisp, int, int, + int, const struct breakpoint_ops *, + int, int, int, unsigned); + + /* Given the address string (second parameter), this method decodes it + and provides the SAL locations related to it. For ordinary breakpoints, + it calls `decode_line_full'. + + This function is called inside `addr_string_to_sals'. */ + void (*decode_linespec) (struct breakpoint *, char **, + struct symtabs_and_lines *); + + /* Return true if this breakpoint explains a signal, but the signal + should still be delivered to the inferior. This is used to make + 'catch signal' interact properly with 'handle'; see + bpstat_explains_signal. */ + enum bpstat_signal_value (*explains_signal) (struct breakpoint *, + enum gdb_signal); + + /* Called after evaluating the breakpoint's condition, + and only if it evaluated true. */ + void (*after_condition_true) (struct bpstats *bs); }; /* Helper for breakpoint_ops->print_recreate implementations. Prints @@ -506,9 +643,6 @@ enum watchpoint_triggered watch_triggered_yes }; -/* This is used to declare the VEC syscalls_to_be_caught. */ -DEF_VEC_I(int); - typedef struct bp_location *bp_location_p; DEF_VEC_P(bp_location_p); @@ -558,6 +692,11 @@ struct breakpoint /* Number of stops at this breakpoint that should be continued automatically before really stopping. */ int ignore_count; + + /* Number of stops at this breakpoint before it will be + disabled. */ + int enable_count; + /* Chain of command lines to execute when this breakpoint is hit. */ struct counted_command_line *commands; @@ -591,8 +730,9 @@ struct breakpoint /* String form of the breakpoint condition (malloc'd), or NULL if there is no condition. */ char *cond_string; - /* String form of exp to use for displaying to the user - (malloc'd), or NULL if none. */ + + /* String form of extra parameters, or NULL if there are none. */ + char *extra_string; /* Holds the address of the related watchpoint_scope breakpoint when using watchpoints on local variables (might the concept of @@ -647,12 +787,12 @@ struct watchpoint struct expression *exp; /* The largest block within which it is valid, or NULL if it is valid anywhere (e.g. consists just of global symbols). */ - struct block *exp_valid_block; + const struct block *exp_valid_block; /* The conditional expression if any. */ struct expression *cond_exp; /* The largest block within which it is valid, or NULL if it is valid anywhere (e.g. consists just of global symbols). */ - struct block *cond_exp_valid_block; + const struct block *cond_exp_valid_block; /* Value of the watchpoint the last time we checked it, or NULL when we do not know the value yet or the value was not readable. VAL is never lazy. */ @@ -683,6 +823,11 @@ struct watchpoint CORE_ADDR hw_wp_mask; }; +/* Return true if BPT is either a software breakpoint or a hardware + breakpoint. */ + +extern int is_breakpoint (const struct breakpoint *bpt); + /* Returns true if BPT is really a watchpoint. */ extern int is_watchpoint (const struct breakpoint *bpt); @@ -741,7 +886,8 @@ extern void bpstat_clear (bpstat *); extern bpstat bpstat_copy (bpstat); extern bpstat bpstat_stop_status (struct address_space *aspace, - CORE_ADDR pc, ptid_t ptid); + CORE_ADDR pc, ptid_t ptid, + const struct target_waitstatus *ws); /* This bpstat_what stuff tells wait_for_inferior what to do with a breakpoint (a challenging task). @@ -865,10 +1011,10 @@ struct bpstat_what bpstat_what (bpstat); bpstat bpstat_find_breakpoint (bpstat, struct breakpoint *); /* Nonzero if a signal that we got in wait() was due to circumstances - explained by the BS. */ -/* Currently that is true if we have hit a breakpoint, or if there is - a watchpoint enabled. */ -#define bpstat_explains_signal(bs) ((bs) != NULL) + explained by the bpstat; and the signal should therefore not be + delivered. */ +extern enum bpstat_signal_value bpstat_explains_signal (bpstat, + enum gdb_signal); /* Nonzero is this bpstat causes a stop. */ extern int bpstat_causes_stop (bpstat); @@ -1046,6 +1192,10 @@ extern void delete_breakpoint (struct breakpoint *); extern void breakpoint_auto_delete (bpstat); +typedef void (*walk_bp_location_callback) (struct bp_location *, void *); + +extern void iterate_over_bp_locations (walk_bp_location_callback); + /* Return the chain of command lines to execute when this breakpoint is hit. */ extern struct command_line *breakpoint_commands (struct breakpoint *b); @@ -1064,7 +1214,9 @@ extern void awatch_command_wrapper (char *, int, int); extern void rwatch_command_wrapper (char *, int, int); extern void tbreak_command (char *, int); +extern struct breakpoint_ops base_breakpoint_ops; extern struct breakpoint_ops bkpt_breakpoint_ops; +extern struct breakpoint_ops tracepoint_breakpoint_ops; extern void initialize_breakpoint_ops (void); @@ -1080,8 +1232,7 @@ extern void add_catch_command (char *name, char *docstring, void (*sfunc) (char *args, int from_tty, struct cmd_list_element *command), - char **(*completer) (struct cmd_list_element *cmd, - char *text, char *word), + completer_ftype *completer, void *user_data_catch, void *user_data_tcatch); @@ -1096,6 +1247,11 @@ extern void int tempflag, int from_tty); +extern void init_catchpoint (struct breakpoint *b, + struct gdbarch *gdbarch, int tempflag, + char *cond_string, + const struct breakpoint_ops *ops); + /* Add breakpoint B on the breakpoint list, and notify the user, the target and breakpoint_created observers of its existence. If INTERNAL is non-zero, the breakpoint number will be allocated from @@ -1117,6 +1273,7 @@ enum breakpoint_create_flags extern int create_breakpoint (struct gdbarch *gdbarch, char *arg, char *cond_string, int thread, + char *extra_string, int parse_condition_and_thread, int tempflag, enum bptype wanted_type, int ignore_count, @@ -1165,7 +1322,7 @@ extern void update_breakpoints_after_exec (void); It is an error to use this function on the process whose id is inferior_ptid. */ -extern int detach_breakpoints (int); +extern int detach_breakpoints (ptid_t ptid); /* This function is called when program space PSPACE is about to be deleted. It takes care of updating breakpoints to not reference @@ -1176,6 +1333,12 @@ extern void set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame); extern void delete_longjmp_breakpoint (int thread); +/* Mark all longjmp breakpoints from THREAD for later deletion. */ +extern void delete_longjmp_breakpoint_at_next_stop (int thread); + +extern struct breakpoint *set_longjmp_breakpoint_for_call_dummy (void); +extern void check_longjmp_breakpoint_for_call_dummy (int thread); + extern void enable_overlay_breakpoints (void); extern void disable_overlay_breakpoints (void); @@ -1277,7 +1440,12 @@ extern void remove_thread_event_breakpoints (void); extern void disable_breakpoints_in_shlibs (void); /* This function returns TRUE if ep is a catchpoint. */ -extern int ep_is_catchpoint (struct breakpoint *); +extern int is_catchpoint (struct breakpoint *); + +/* Shared helper function (MI and CLI) for creating and installing + a shared object event catchpoint. */ +extern void add_solib_catchpoint (char *arg, int is_load, int is_temp, + int enabled); /* Enable breakpoints and delete when hit. Called with ARG == NULL deletes all breakpoints. */ @@ -1382,11 +1550,16 @@ extern struct breakpoint *iterate_over_breakpoints (int (*) (struct breakpoint * have been inlined. */ extern int pc_at_non_inline_function (struct address_space *aspace, - CORE_ADDR pc); + CORE_ADDR pc, + const struct target_waitstatus *ws); extern int user_breakpoint_p (struct breakpoint *); /* Attempt to determine architecture of location identified by SAL. */ extern struct gdbarch *get_sal_arch (struct symtab_and_line sal); +extern void handle_solib_event (void); + +extern void breakpoint_free_objfile (struct objfile *objfile); + #endif /* !defined (BREAKPOINT_H) */ diff --git a/contrib/gdb-7/gdb/bsd-kvm.c b/contrib/gdb-7/gdb/bsd-kvm.c index 39bd39639d..82694bd898 100644 --- a/contrib/gdb-7/gdb/bsd-kvm.c +++ b/contrib/gdb-7/gdb/bsd-kvm.c @@ -1,6 +1,6 @@ /* BSD Kernel Data Access Library (libkvm) interface. - Copyright (C) 2004-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/bsd-kvm.h b/contrib/gdb-7/gdb/bsd-kvm.h index d06e26ab1a..e31b51279d 100644 --- a/contrib/gdb-7/gdb/bsd-kvm.h +++ b/contrib/gdb-7/gdb/bsd-kvm.h @@ -1,6 +1,6 @@ /* BSD Kernel Data Access Library (libkvm) interface. - Copyright (C) 2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/bsd-uthread.c b/contrib/gdb-7/gdb/bsd-uthread.c index ea9831be9b..74716adb3b 100644 --- a/contrib/gdb-7/gdb/bsd-uthread.c +++ b/contrib/gdb-7/gdb/bsd-uthread.c @@ -1,6 +1,6 @@ /* BSD user-level threads support. - Copyright (C) 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -93,7 +93,7 @@ bsd_uthread_set_collect_uthread (struct gdbarch *gdbarch, static void bsd_uthread_check_magic (CORE_ADDR addr) { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); ULONGEST magic = read_memory_unsigned_integer (addr, 4, byte_order); if (magic != BSD_UTHREAD_PTHREAD_MAGIC) @@ -137,7 +137,7 @@ bsd_uthread_lookup_address (const char *name, struct objfile *objfile) static int bsd_uthread_lookup_offset (const char *name, struct objfile *objfile) { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); CORE_ADDR addr; addr = bsd_uthread_lookup_address (name, objfile); @@ -150,7 +150,7 @@ bsd_uthread_lookup_offset (const char *name, struct objfile *objfile) static CORE_ADDR bsd_uthread_read_memory_address (CORE_ADDR addr) { - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; return read_memory_typed_address (addr, ptr_type); } @@ -161,7 +161,7 @@ bsd_uthread_read_memory_address (CORE_ADDR addr) static int bsd_uthread_activate (struct objfile *objfile) { - struct gdbarch *gdbarch = target_gdbarch; + struct gdbarch *gdbarch = target_gdbarch (); struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data); /* Skip if the thread stratum has already been activated. */ @@ -349,7 +349,7 @@ static ptid_t bsd_uthread_wait (struct target_ops *ops, ptid_t ptid, struct target_waitstatus *status, int options) { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); CORE_ADDR addr; struct target_ops *beneath = find_target_beneath (ops); @@ -397,7 +397,7 @@ bsd_uthread_wait (struct target_ops *ops, static void bsd_uthread_resume (struct target_ops *ops, - ptid_t ptid, int step, enum target_signal sig) + ptid_t ptid, int step, enum gdb_signal sig) { /* Pass the request to the layer beneath. */ struct target_ops *beneath = find_target_beneath (ops); @@ -407,7 +407,7 @@ bsd_uthread_resume (struct target_ops *ops, static int bsd_uthread_thread_alive (struct target_ops *ops, ptid_t ptid) { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); struct target_ops *beneath = find_target_beneath (ops); CORE_ADDR addr = ptid_get_tid (inferior_ptid); @@ -484,7 +484,7 @@ static char *bsd_uthread_state[] = static char * bsd_uthread_extra_thread_info (struct thread_info *info) { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); CORE_ADDR addr = ptid_get_tid (info->ptid); if (addr != 0) diff --git a/contrib/gdb-7/gdb/bsd-uthread.h b/contrib/gdb-7/gdb/bsd-uthread.h index 9145507f21..7de84ea423 100644 --- a/contrib/gdb-7/gdb/bsd-uthread.h +++ b/contrib/gdb-7/gdb/bsd-uthread.h @@ -1,6 +1,6 @@ /* BSD user-level threads support. - Copyright (C) 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/btrace.c b/contrib/gdb-7/gdb/btrace.c new file mode 100644 index 0000000000..c39a32d763 --- /dev/null +++ b/contrib/gdb-7/gdb/btrace.c @@ -0,0 +1,543 @@ +/* Branch trace support for GDB, the GNU debugger. + + Copyright (C) 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + 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 "btrace.h" +#include "gdbthread.h" +#include "exceptions.h" +#include "inferior.h" +#include "target.h" +#include "record.h" +#include "symtab.h" +#include "disasm.h" +#include "source.h" +#include "filenames.h" +#include "xml-support.h" + +/* Print a record debug message. Use do ... while (0) to avoid ambiguities + when used in if statements. */ + +#define DEBUG(msg, args...) \ + do \ + { \ + if (record_debug != 0) \ + fprintf_unfiltered (gdb_stdlog, \ + "[btrace] " msg "\n", ##args); \ + } \ + while (0) + +#define DEBUG_FTRACE(msg, args...) DEBUG ("[ftrace] " msg, ##args) + +/* Initialize the instruction iterator. */ + +static void +btrace_init_insn_iterator (struct btrace_thread_info *btinfo) +{ + DEBUG ("init insn iterator"); + + btinfo->insn_iterator.begin = 1; + btinfo->insn_iterator.end = 0; +} + +/* Initialize the function iterator. */ + +static void +btrace_init_func_iterator (struct btrace_thread_info *btinfo) +{ + DEBUG ("init func iterator"); + + btinfo->func_iterator.begin = 1; + btinfo->func_iterator.end = 0; +} + +/* Compute the instruction trace from the block trace. */ + +static VEC (btrace_inst_s) * +compute_itrace (VEC (btrace_block_s) *btrace) +{ + VEC (btrace_inst_s) *itrace; + struct gdbarch *gdbarch; + unsigned int b; + + DEBUG ("compute itrace"); + + itrace = NULL; + gdbarch = target_gdbarch (); + b = VEC_length (btrace_block_s, btrace); + + while (b-- != 0) + { + btrace_block_s *block; + CORE_ADDR pc; + + block = VEC_index (btrace_block_s, btrace, b); + pc = block->begin; + + /* Add instructions for this block. */ + for (;;) + { + btrace_inst_s *inst; + int size; + + /* We should hit the end of the block. Warn if we went too far. */ + if (block->end < pc) + { + warning (_("Recorded trace may be corrupted.")); + break; + } + + inst = VEC_safe_push (btrace_inst_s, itrace, NULL); + inst->pc = pc; + + /* We're done once we pushed the instruction at the end. */ + if (block->end == pc) + break; + + size = gdb_insn_length (gdbarch, pc); + + /* Make sure we terminate if we fail to compute the size. */ + if (size <= 0) + { + warning (_("Recorded trace may be incomplete.")); + break; + } + + pc += size; + } + } + + return itrace; +} + +/* Return the function name of a recorded function segment for printing. + This function never returns NULL. */ + +static const char * +ftrace_print_function_name (struct btrace_func *bfun) +{ + struct minimal_symbol *msym; + struct symbol *sym; + + msym = bfun->msym; + sym = bfun->sym; + + if (sym != NULL) + return SYMBOL_PRINT_NAME (sym); + + if (msym != NULL) + return SYMBOL_PRINT_NAME (msym); + + return ""; +} + +/* Return the file name of a recorded function segment for printing. + This function never returns NULL. */ + +static const char * +ftrace_print_filename (struct btrace_func *bfun) +{ + struct symbol *sym; + const char *filename; + + sym = bfun->sym; + + if (sym != NULL) + filename = symtab_to_filename_for_display (sym->symtab); + else + filename = ""; + + return filename; +} + +/* Print an ftrace debug status message. */ + +static void +ftrace_debug (struct btrace_func *bfun, const char *prefix) +{ + DEBUG_FTRACE ("%s: fun = %s, file = %s, lines = [%d; %d], insn = [%u; %u]", + prefix, ftrace_print_function_name (bfun), + ftrace_print_filename (bfun), bfun->lbegin, bfun->lend, + bfun->ibegin, bfun->iend); +} + +/* Initialize a recorded function segment. */ + +static void +ftrace_init_func (struct btrace_func *bfun, struct minimal_symbol *mfun, + struct symbol *fun, unsigned int idx) +{ + bfun->msym = mfun; + bfun->sym = fun; + bfun->lbegin = INT_MAX; + bfun->lend = 0; + bfun->ibegin = idx; + bfun->iend = idx; +} + +/* Check whether the function has changed. */ + +static int +ftrace_function_switched (struct btrace_func *bfun, + struct minimal_symbol *mfun, struct symbol *fun) +{ + struct minimal_symbol *msym; + struct symbol *sym; + + /* The function changed if we did not have one before. */ + if (bfun == NULL) + return 1; + + msym = bfun->msym; + sym = bfun->sym; + + /* If the minimal symbol changed, we certainly switched functions. */ + if (mfun != NULL && msym != NULL + && strcmp (SYMBOL_LINKAGE_NAME (mfun), SYMBOL_LINKAGE_NAME (msym)) != 0) + return 1; + + /* If the symbol changed, we certainly switched functions. */ + if (fun != NULL && sym != NULL) + { + const char *bfname, *fname; + + /* Check the function name. */ + if (strcmp (SYMBOL_LINKAGE_NAME (fun), SYMBOL_LINKAGE_NAME (sym)) != 0) + return 1; + + /* Check the location of those functions, as well. */ + bfname = symtab_to_fullname (sym->symtab); + fname = symtab_to_fullname (fun->symtab); + if (filename_cmp (fname, bfname) != 0) + return 1; + } + + return 0; +} + +/* Check if we should skip this file when generating the function call + history. We would want to do that if, say, a macro that is defined + in another file is expanded in this function. */ + +static int +ftrace_skip_file (struct btrace_func *bfun, const char *filename) +{ + struct symbol *sym; + const char *bfile; + + sym = bfun->sym; + + if (sym != NULL) + bfile = symtab_to_fullname (sym->symtab); + else + bfile = ""; + + if (filename == NULL) + filename = ""; + + return (filename_cmp (bfile, filename) != 0); +} + +/* Compute the function trace from the instruction trace. */ + +static VEC (btrace_func_s) * +compute_ftrace (VEC (btrace_inst_s) *itrace) +{ + VEC (btrace_func_s) *ftrace; + struct btrace_inst *binst; + struct btrace_func *bfun; + unsigned int idx; + + DEBUG ("compute ftrace"); + + ftrace = NULL; + bfun = NULL; + + for (idx = 0; VEC_iterate (btrace_inst_s, itrace, idx, binst); ++idx) + { + struct symtab_and_line sal; + struct minimal_symbol *mfun; + struct symbol *fun; + const char *filename; + CORE_ADDR pc; + + pc = binst->pc; + + /* Try to determine the function we're in. We use both types of symbols + to avoid surprises when we sometimes get a full symbol and sometimes + only a minimal symbol. */ + fun = find_pc_function (pc); + mfun = lookup_minimal_symbol_by_pc (pc); + + if (fun == NULL && mfun == NULL) + { + DEBUG_FTRACE ("no symbol at %u, pc=%s", idx, + core_addr_to_string_nz (pc)); + continue; + } + + /* If we're switching functions, we start over. */ + if (ftrace_function_switched (bfun, mfun, fun)) + { + bfun = VEC_safe_push (btrace_func_s, ftrace, NULL); + + ftrace_init_func (bfun, mfun, fun, idx); + ftrace_debug (bfun, "init"); + } + + /* Update the instruction range. */ + bfun->iend = idx; + ftrace_debug (bfun, "update insns"); + + /* Let's see if we have source correlation, as well. */ + sal = find_pc_line (pc, 0); + if (sal.symtab == NULL || sal.line == 0) + { + DEBUG_FTRACE ("no lines at %u, pc=%s", idx, + core_addr_to_string_nz (pc)); + continue; + } + + /* Check if we switched files. This could happen if, say, a macro that + is defined in another file is expanded here. */ + filename = symtab_to_fullname (sal.symtab); + if (ftrace_skip_file (bfun, filename)) + { + DEBUG_FTRACE ("ignoring file at %u, pc=%s, file=%s", idx, + core_addr_to_string_nz (pc), filename); + continue; + } + + /* Update the line range. */ + bfun->lbegin = min (bfun->lbegin, sal.line); + bfun->lend = max (bfun->lend, sal.line); + ftrace_debug (bfun, "update lines"); + } + + return ftrace; +} + +/* See btrace.h. */ + +void +btrace_enable (struct thread_info *tp) +{ + if (tp->btrace.target != NULL) + return; + + if (!target_supports_btrace ()) + error (_("Target does not support branch tracing.")); + + DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + tp->btrace.target = target_enable_btrace (tp->ptid); +} + +/* See btrace.h. */ + +void +btrace_disable (struct thread_info *tp) +{ + struct btrace_thread_info *btp = &tp->btrace; + int errcode = 0; + + if (btp->target == NULL) + return; + + DEBUG ("disable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + target_disable_btrace (btp->target); + btp->target = NULL; + + btrace_clear (tp); +} + +/* See btrace.h. */ + +void +btrace_teardown (struct thread_info *tp) +{ + struct btrace_thread_info *btp = &tp->btrace; + int errcode = 0; + + if (btp->target == NULL) + return; + + DEBUG ("teardown thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + target_teardown_btrace (btp->target); + btp->target = NULL; + + btrace_clear (tp); +} + +/* See btrace.h. */ + +void +btrace_fetch (struct thread_info *tp) +{ + struct btrace_thread_info *btinfo; + VEC (btrace_block_s) *btrace; + + DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + btinfo = &tp->btrace; + if (btinfo->target == NULL) + return; + + btrace = target_read_btrace (btinfo->target, btrace_read_new); + if (VEC_empty (btrace_block_s, btrace)) + return; + + btrace_clear (tp); + + btinfo->btrace = btrace; + btinfo->itrace = compute_itrace (btinfo->btrace); + btinfo->ftrace = compute_ftrace (btinfo->itrace); + + /* Initialize branch trace iterators. */ + btrace_init_insn_iterator (btinfo); + btrace_init_func_iterator (btinfo); +} + +/* See btrace.h. */ + +void +btrace_clear (struct thread_info *tp) +{ + struct btrace_thread_info *btinfo; + + DEBUG ("clear thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + btinfo = &tp->btrace; + + VEC_free (btrace_block_s, btinfo->btrace); + VEC_free (btrace_inst_s, btinfo->itrace); + VEC_free (btrace_func_s, btinfo->ftrace); + + btinfo->btrace = NULL; + btinfo->itrace = NULL; + btinfo->ftrace = NULL; +} + +/* See btrace.h. */ + +void +btrace_free_objfile (struct objfile *objfile) +{ + struct thread_info *tp; + + DEBUG ("free objfile"); + + ALL_THREADS (tp) + btrace_clear (tp); +} + +#if defined (HAVE_LIBEXPAT) + +/* Check the btrace document version. */ + +static void +check_xml_btrace_version (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC (gdb_xml_value_s) *attributes) +{ + const char *version = xml_find_attribute (attributes, "version")->value; + + if (strcmp (version, "1.0") != 0) + gdb_xml_error (parser, _("Unsupported btrace version: \"%s\""), version); +} + +/* Parse a btrace "block" xml record. */ + +static void +parse_xml_btrace_block (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC (gdb_xml_value_s) *attributes) +{ + VEC (btrace_block_s) **btrace; + struct btrace_block *block; + ULONGEST *begin, *end; + + btrace = user_data; + block = VEC_safe_push (btrace_block_s, *btrace, NULL); + + begin = xml_find_attribute (attributes, "begin")->value; + end = xml_find_attribute (attributes, "end")->value; + + block->begin = *begin; + block->end = *end; +} + +static const struct gdb_xml_attribute block_attributes[] = { + { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute btrace_attributes[] = { + { "version", GDB_XML_AF_NONE, NULL, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element btrace_children[] = { + { "block", block_attributes, NULL, + GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, parse_xml_btrace_block, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element btrace_elements[] = { + { "btrace", btrace_attributes, btrace_children, GDB_XML_EF_NONE, + check_xml_btrace_version, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +#endif /* defined (HAVE_LIBEXPAT) */ + +/* See btrace.h. */ + +VEC (btrace_block_s) * +parse_xml_btrace (const char *buffer) +{ + VEC (btrace_block_s) *btrace = NULL; + struct cleanup *cleanup; + int errcode; + +#if defined (HAVE_LIBEXPAT) + + cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace); + errcode = gdb_xml_parse_quick (_("btrace"), "btrace.dtd", btrace_elements, + buffer, &btrace); + if (errcode != 0) + { + do_cleanups (cleanup); + return NULL; + } + + /* Keep parse results. */ + discard_cleanups (cleanup); + +#else /* !defined (HAVE_LIBEXPAT) */ + + error (_("Cannot process branch trace. XML parsing is not supported.")); + +#endif /* !defined (HAVE_LIBEXPAT) */ + + return btrace; +} diff --git a/contrib/gdb-7/gdb/btrace.h b/contrib/gdb-7/gdb/btrace.h new file mode 100644 index 0000000000..bd8425dea8 --- /dev/null +++ b/contrib/gdb-7/gdb/btrace.h @@ -0,0 +1,142 @@ +/* Branch trace support for GDB, the GNU debugger. + + Copyright (C) 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. . + + 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 BTRACE_H +#define BTRACE_H + +/* Branch tracing (btrace) is a per-thread control-flow execution trace of the + inferior. For presentation purposes, the branch trace is represented as a + list of sequential control-flow blocks, one such list per thread. */ + +#include "btrace-common.h" + +struct thread_info; + +/* A branch trace instruction. + + This represents a single instruction in a branch trace. */ +struct btrace_inst +{ + /* The address of this instruction. */ + CORE_ADDR pc; +}; + +/* A branch trace function. + + This represents a function segment in a branch trace, i.e. a consecutive + number of instructions belonging to the same function. */ +struct btrace_func +{ + /* The full and minimal symbol for the function. One of them may be NULL. */ + struct minimal_symbol *msym; + struct symbol *sym; + + /* The source line range of this function segment (both inclusive). */ + int lbegin, lend; + + /* The instruction number range in the instruction trace corresponding + to this function segment (both inclusive). */ + unsigned int ibegin, iend; +}; + +/* Branch trace may also be represented as a vector of: + + - branch trace instructions starting with the oldest instruction. + - branch trace functions starting with the oldest function. */ +typedef struct btrace_inst btrace_inst_s; +typedef struct btrace_func btrace_func_s; + +/* Define functions operating on branch trace vectors. */ +DEF_VEC_O (btrace_inst_s); +DEF_VEC_O (btrace_func_s); + +/* Branch trace iteration state for "record instruction-history". */ +struct btrace_insn_iterator +{ + /* The instruction index range from begin (inclusive) to end (exclusive) + that has been covered last time. + If end < begin, the branch trace has just been updated. */ + unsigned int begin; + unsigned int end; +}; + +/* Branch trace iteration state for "record function-call-history". */ +struct btrace_func_iterator +{ + /* The function index range from begin (inclusive) to end (exclusive) + that has been covered last time. + If end < begin, the branch trace has just been updated. */ + unsigned int begin; + unsigned int end; +}; + +/* Branch trace information per thread. + + This represents the branch trace configuration as well as the entry point + into the branch trace data. For the latter, it also contains the index into + an array of branch trace blocks used for iterating though the branch trace + blocks of a thread. */ +struct btrace_thread_info +{ + /* The target branch trace information for this thread. + + This contains the branch trace configuration as well as any + target-specific information necessary for implementing branch tracing on + the underlying architecture. */ + struct btrace_target_info *target; + + /* The current branch trace for this thread. */ + VEC (btrace_block_s) *btrace; + VEC (btrace_inst_s) *itrace; + VEC (btrace_func_s) *ftrace; + + /* The instruction history iterator. */ + struct btrace_insn_iterator insn_iterator; + + /* The function call history iterator. */ + struct btrace_func_iterator func_iterator; +}; + +/* Enable branch tracing for a thread. */ +extern void btrace_enable (struct thread_info *tp); + +/* Disable branch tracing for a thread. + This will also delete the current branch trace data. */ +extern void btrace_disable (struct thread_info *); + +/* Disable branch tracing for a thread during teardown. + This is similar to btrace_disable, except that it will use + target_teardown_btrace instead of target_disable_btrace. */ +extern void btrace_teardown (struct thread_info *); + +/* Fetch the branch trace for a single thread. */ +extern void btrace_fetch (struct thread_info *); + +/* Clear the branch trace for a single thread. */ +extern void btrace_clear (struct thread_info *); + +/* Clear the branch trace for all threads when an object file goes away. */ +extern void btrace_free_objfile (struct objfile *); + +/* Parse a branch trace xml document into a block vector. */ +extern VEC (btrace_block_s) *parse_xml_btrace (const char*); + +#endif /* BTRACE_H */ diff --git a/contrib/gdb-7/gdb/buildsym.c b/contrib/gdb-7/gdb/buildsym.c index 38bde22e20..4d861a5ccf 100644 --- a/contrib/gdb-7/gdb/buildsym.c +++ b/contrib/gdb-7/gdb/buildsym.c @@ -1,5 +1,5 @@ /* Support routines for building symbol tables in GDB's internal format. - Copyright (C) 1986-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -49,7 +49,7 @@ #include "buildsym.h" /* Our own declarations. */ #undef EXTERN -/* For cleanup_undefined_types and finish_global_stabs (somewhat +/* For cleanup_undefined_stabs_types and finish_global_stabs (somewhat questionable--see comment where we call them). */ #include "stabsread.h" @@ -83,8 +83,31 @@ static struct obstack pending_addrmap_obstack; the end, then we just toss the addrmap. */ static int pending_addrmap_interesting; +/* An obstack used for allocating pending blocks. */ + +static struct obstack pending_block_obstack; + +/* List of blocks already made (lexical contexts already closed). + This is used at the end to make the blockvector. */ + +struct pending_block + { + struct pending_block *next; + struct block *block; + }; + +/* Pointer to the head of a linked list of symbol blocks which have + already been finalized (lexical contexts already closed) and which + are just waiting to be built into a blockvector when finalizing the + associated symtab. */ + +static struct pending_block *pending_blocks; static int compare_line_numbers (const void *ln1p, const void *ln2p); + +static void record_pending_block (struct objfile *objfile, + struct block *block, + struct pending_block *opblock); /* Initial sizes of data structures. These are realloc'd larger if @@ -97,20 +120,6 @@ static int compare_line_numbers (const void *ln1p, const void *ln2p); /* Maintain the lists of symbols and blocks. */ -/* Add a pending list to free_pendings. */ -void -add_free_pendings (struct pending *list) -{ - struct pending *link = list; - - if (list) - { - while (link->next) link = link->next; - link->next = free_pendings; - free_pendings = list; - } -} - /* Add a symbol to one of the lists of symbols. */ void @@ -151,7 +160,7 @@ struct symbol * find_symbol_in_list (struct pending *list, char *name, int length) { int j; - char *pp; + const char *pp; while (list != NULL) { @@ -215,20 +224,23 @@ really_free_pendings (void *dummy) void free_pending_blocks (void) { - /* The links are made in the objfile_obstack, so we only need to - reset PENDING_BLOCKS. */ - pending_blocks = NULL; + if (pending_blocks != NULL) + { + obstack_free (&pending_block_obstack, NULL); + pending_blocks = NULL; + } } /* Take one of the lists of symbols and make a block from it. Keep the order the symbols have in the list (reversed from the input file). Put the block on the list of pending blocks. */ -struct block * -finish_block (struct symbol *symbol, struct pending **listhead, - struct pending_block *old_blocks, - CORE_ADDR start, CORE_ADDR end, - struct objfile *objfile) +static struct block * +finish_block_internal (struct symbol *symbol, struct pending **listhead, + struct pending_block *old_blocks, + CORE_ADDR start, CORE_ADDR end, + struct objfile *objfile, + int is_global, int expandable) { struct gdbarch *gdbarch = get_objfile_arch (objfile); struct pending *next, *next1; @@ -236,7 +248,9 @@ finish_block (struct symbol *symbol, struct pending **listhead, struct pending_block *pblock; struct pending_block *opblock; - block = allocate_block (&objfile->objfile_obstack); + block = (is_global + ? allocate_global_block (&objfile->objfile_obstack) + : allocate_block (&objfile->objfile_obstack)); if (symbol) { @@ -245,15 +259,20 @@ finish_block (struct symbol *symbol, struct pending **listhead, } else { - BLOCK_DICT (block) = dict_create_hashed (&objfile->objfile_obstack, - *listhead); + if (expandable) + { + BLOCK_DICT (block) = dict_create_hashed_expandable (); + dict_add_pending (BLOCK_DICT (block), *listhead); + } + else + { + BLOCK_DICT (block) = + dict_create_hashed (&objfile->objfile_obstack, *listhead); + } } BLOCK_START (block) = start; BLOCK_END (block) = end; - /* Superblock filled in when containing block is made. */ - BLOCK_SUPERBLOCK (block) = NULL; - BLOCK_NAMESPACE (block) = NULL; /* Put the block in as the value of the symbol that names it. */ @@ -271,7 +290,10 @@ finish_block (struct symbol *symbol, struct pending **listhead, parameter symbols. */ int nparams = 0, iparams; struct symbol *sym; - ALL_BLOCK_SYMBOLS (block, iter, sym) + + /* Here we want to directly access the dictionary, because + we haven't fully initialized the block yet. */ + ALL_DICT_SYMBOLS (BLOCK_DICT (block), iter, sym) { if (SYMBOL_IS_ARGUMENT (sym)) nparams++; @@ -283,7 +305,9 @@ finish_block (struct symbol *symbol, struct pending **listhead, TYPE_ALLOC (ftype, nparams * sizeof (struct field)); iparams = 0; - ALL_BLOCK_SYMBOLS (block, iter, sym) + /* Here we want to directly access the dictionary, because + we haven't fully initialized the block yet. */ + ALL_DICT_SYMBOLS (BLOCK_DICT (block), iter, sym) { if (iparams == nparams) break; @@ -392,6 +416,15 @@ finish_block (struct symbol *symbol, struct pending **listhead, return block; } +struct block * +finish_block (struct symbol *symbol, struct pending **listhead, + struct pending_block *old_blocks, + CORE_ADDR start, CORE_ADDR end, + struct objfile *objfile) +{ + return finish_block_internal (symbol, listhead, old_blocks, + start, end, objfile, 0, 0); +} /* Record BLOCK on the list of all blocks in the file. Put it after OPBLOCK, or at the beginning if opblock is NULL. This puts the @@ -400,14 +433,17 @@ finish_block (struct symbol *symbol, struct pending **listhead, Allocate the pending block struct in the objfile_obstack to save time. This wastes a little space. FIXME: Is it worth it? */ -void +static void record_pending_block (struct objfile *objfile, struct block *block, struct pending_block *opblock) { struct pending_block *pblock; + if (pending_blocks == NULL) + obstack_init (&pending_block_obstack); + pblock = (struct pending_block *) - obstack_alloc (&objfile->objfile_obstack, sizeof (struct pending_block)); + obstack_alloc (&pending_block_obstack, sizeof (struct pending_block)); pblock->block = block; if (opblock) { @@ -492,10 +528,13 @@ make_blockvector (struct objfile *objfile) = addrmap_create_fixed (pending_addrmap, &objfile->objfile_obstack); else BLOCKVECTOR_MAP (blockvector) = 0; - + /* Some compilers output blocks in the wrong order, but we depend on their being in the right order so we can binary search. Check the - order and moan about it. */ + order and moan about it. + Note: Remember that the first two blocks are the global and static + blocks. We could special case that fact and begin checking at block 2. + To avoid making that assumption we do not. */ if (BLOCKVECTOR_NBLOCKS (blockvector) > 1) { for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++) @@ -565,7 +604,7 @@ start_subfile (const char *name, const char *dirname) current_subfile = subfile; /* Save its name and compilation directory name. */ - subfile->name = (name == NULL) ? NULL : xstrdup (name); + subfile->name = xstrdup (name); subfile->dirname = (dirname == NULL) ? NULL : xstrdup (dirname); /* Initialize line-number recording for this subfile. */ @@ -642,7 +681,7 @@ patch_subfile_names (struct subfile *subfile, char *name) { subfile->dirname = subfile->name; subfile->name = xstrdup (name); - last_source_file = name; + set_last_source_file (name); /* Default the source language to whatever can be deduced from the filename. If nothing can be deduced (such as for a C/C++ @@ -796,9 +835,22 @@ compare_line_numbers (const void *ln1p, const void *ln2p) lowest address of objects in the file (or 0 if not known). */ void -start_symtab (char *name, char *dirname, CORE_ADDR start_addr) +start_symtab (const char *name, const char *dirname, CORE_ADDR start_addr) { - last_source_file = name; + restart_symtab (start_addr); + set_last_source_file (name); + start_subfile (name, dirname); +} + +/* Restart compilation for a symtab. + This is used when a symtab is built from multiple sources. + The symtab is first built with start_symtab and then for each additional + piece call restart_symtab. */ + +void +restart_symtab (CORE_ADDR start_addr) +{ + set_last_source_file (NULL); last_source_start_addr = start_addr; file_symbols = NULL; global_symbols = NULL; @@ -820,10 +872,8 @@ start_symtab (char *name, char *dirname, CORE_ADDR start_addr) /* Initialize the list of sub source files with one entry for this file (the top-level source file). */ - subfiles = NULL; current_subfile = NULL; - start_subfile (name, dirname); } /* Subroutine of end_symtab to simplify it. Look for a subfile that @@ -903,7 +953,7 @@ watch_main_source_file_lossage (void) } } -/* Helper function for qsort. Parametes are `struct block *' pointers, +/* Helper function for qsort. Parameters are `struct block *' pointers, function sorts them in descending order by their BLOCK_START. */ static int @@ -916,38 +966,46 @@ block_compar (const void *ap, const void *bp) - (BLOCK_START (b) < BLOCK_START (a))); } -/* Finish the symbol definitions for one main source file, close off - all the lexical contexts for that file (creating struct block's for - them), then make the struct symtab for that file and put it in the - list of all such. +/* Reset globals used to build symtabs. */ - END_ADDR is the address of the end of the file's text. SECTION is - the section number (in objfile->section_offsets) of the blockvector - and linetable. +static void +reset_symtab_globals (void) +{ + set_last_source_file (NULL); + current_subfile = NULL; + pending_macros = NULL; + if (pending_addrmap) + { + obstack_free (&pending_addrmap_obstack, NULL); + pending_addrmap = NULL; + } +} - Note that it is possible for end_symtab() to return NULL. In - particular, for the DWARF case at least, it will return NULL when - it finds a compilation unit that has exactly one DIE, a - TAG_compile_unit DIE. This can happen when we link in an object - file that was compiled from an empty source file. Returning NULL - is probably not the correct thing to do, because then gdb will - never know about this empty file (FIXME). */ +/* Implementation of the first part of end_symtab. It allows modifying + STATIC_BLOCK before it gets finalized by end_symtab_from_static_block. + If the returned value is NULL there is no blockvector created for + this symtab (you still must call end_symtab_from_static_block). -struct symtab * -end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) -{ - struct symtab *symtab = NULL; - struct blockvector *blockvector; - struct subfile *subfile; - struct context_stack *cstk; - struct subfile *nextsub; + END_ADDR is the same as for end_symtab: the address of the end of the + file's text. + + If EXPANDABLE is non-zero the STATIC_BLOCK dictionary is made + expandable. + + If REQUIRED is non-zero, then a symtab is created even if it does + not contain any symbols. */ +struct block * +end_symtab_get_static_block (CORE_ADDR end_addr, struct objfile *objfile, + int expandable, int required) +{ /* Finish the lexical context of the last function in the file; pop the context stack. */ if (context_stack_depth > 0) { - cstk = pop_context (); + struct context_stack *cstk = pop_context (); + /* Make a block for the local symbols within. */ finish_block (cstk->name, &local_symbols, cstk->old_blocks, cstk->start_addr, end_addr, objfile); @@ -967,6 +1025,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) /* Reordered executables may have out of order pending blocks; if OBJF_REORDERED is true, then sort the pending blocks. */ + if ((objfile->flags & OBJF_REORDERED) && pending_blocks) { unsigned count = 0; @@ -997,33 +1056,67 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) (this needs to be done before the finish_blocks so that file_symbols is still good). - Both cleanup_undefined_types and finish_global_stabs are stabs + Both cleanup_undefined_stabs_types and finish_global_stabs are stabs specific, but harmless for other symbol readers, since on gdb startup or when finished reading stabs, the state is set so these are no-ops. FIXME: Is this handled right in case of QUIT? Can we make this cleaner? */ - cleanup_undefined_types (objfile); + cleanup_undefined_stabs_types (objfile); finish_global_stabs (objfile); - if (pending_blocks == NULL + if (!required + && pending_blocks == NULL && file_symbols == NULL && global_symbols == NULL && have_line_numbers == 0 && pending_macros == NULL) { - /* Ignore symtabs that have no functions with real debugging - info. */ + /* Ignore symtabs that have no functions with real debugging info. */ + return NULL; + } + else + { + /* Define the STATIC_BLOCK. */ + return finish_block_internal (NULL, &file_symbols, NULL, + last_source_start_addr, end_addr, objfile, + 0, expandable); + } +} + +/* Implementation of the second part of end_symtab. Pass STATIC_BLOCK + as value returned by end_symtab_get_static_block. + + SECTION is the same as for end_symtab: the section number + (in objfile->section_offsets) of the blockvector and linetable. + + If EXPANDABLE is non-zero the GLOBAL_BLOCK dictionary is made + expandable. */ + +struct symtab * +end_symtab_from_static_block (struct block *static_block, + struct objfile *objfile, int section, + int expandable) +{ + struct symtab *symtab = NULL; + struct blockvector *blockvector; + struct subfile *subfile; + struct subfile *nextsub; + + if (static_block == NULL) + { + /* Ignore symtabs that have no functions with real debugging info. */ blockvector = NULL; } else { - /* Define the STATIC_BLOCK & GLOBAL_BLOCK, and build the + CORE_ADDR end_addr = BLOCK_END (static_block); + + /* Define after STATIC_BLOCK also GLOBAL_BLOCK, and build the blockvector. */ - finish_block (0, &file_symbols, 0, last_source_start_addr, - end_addr, objfile); - finish_block (0, &global_symbols, 0, last_source_start_addr, - end_addr, objfile); + finish_block_internal (NULL, &global_symbols, NULL, + last_source_start_addr, end_addr, objfile, + 1, expandable); blockvector = make_blockvector (objfile); } @@ -1122,7 +1215,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) { /* Since we are ignoring that subfile, we also need to unlink the associated empty symtab that we created. - Otherwise, we can into trouble because various parts + Otherwise, we can run into trouble because various parts such as the block-vector are uninitialized whereas the rest of the code assumes that they are. @@ -1163,6 +1256,14 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) if (symtab) { symtab->primary = 1; + + if (symtab->blockvector) + { + struct block *b = BLOCKVECTOR_BLOCK (symtab->blockvector, + GLOBAL_BLOCK); + + set_block_symtab (b, symtab); + } } /* Default any symbols without a specified symtab to the primary @@ -1183,24 +1284,128 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) 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)) + /* Note that we only want to fix up symbols from the local + blocks, not blocks coming from included symtabs. That is why + we use ALL_DICT_SYMBOLS here and not ALL_BLOCK_SYMBOLS. */ + ALL_DICT_SYMBOLS (BLOCK_DICT (block), iter, sym) if (SYMBOL_SYMTAB (sym) == NULL) SYMBOL_SYMTAB (sym) = symtab; } } - last_source_file = NULL; - current_subfile = NULL; - pending_macros = NULL; - if (pending_addrmap) + reset_symtab_globals (); + + return symtab; +} + +/* Finish the symbol definitions for one main source file, close off + all the lexical contexts for that file (creating struct block's for + them), then make the struct symtab for that file and put it in the + list of all such. + + END_ADDR is the address of the end of the file's text. SECTION is + the section number (in objfile->section_offsets) of the blockvector + and linetable. + + Note that it is possible for end_symtab() to return NULL. In + particular, for the DWARF case at least, it will return NULL when + it finds a compilation unit that has exactly one DIE, a + TAG_compile_unit DIE. This can happen when we link in an object + file that was compiled from an empty source file. Returning NULL + is probably not the correct thing to do, because then gdb will + never know about this empty file (FIXME). + + If you need to modify STATIC_BLOCK before it is finalized you should + call end_symtab_get_static_block and end_symtab_from_static_block + yourself. */ + +struct symtab * +end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) +{ + struct block *static_block; + + static_block = end_symtab_get_static_block (end_addr, objfile, 0, 0); + return end_symtab_from_static_block (static_block, objfile, section, 0); +} + +/* Same as end_symtab except create a symtab that can be later added to. */ + +struct symtab * +end_expandable_symtab (CORE_ADDR end_addr, struct objfile *objfile, + int section) +{ + struct block *static_block; + + static_block = end_symtab_get_static_block (end_addr, objfile, 1, 0); + return end_symtab_from_static_block (static_block, objfile, section, 1); +} + +/* Subroutine of augment_type_symtab to simplify it. + Attach SYMTAB to all symbols in PENDING_LIST that don't have one. */ + +static void +set_missing_symtab (struct pending *pending_list, struct symtab *symtab) +{ + struct pending *pending; + int i; + + for (pending = pending_list; pending != NULL; pending = pending->next) { - obstack_free (&pending_addrmap_obstack, NULL); - pending_addrmap = NULL; + for (i = 0; i < pending->nsyms; ++i) + { + if (SYMBOL_SYMTAB (pending->symbol[i]) == NULL) + SYMBOL_SYMTAB (pending->symbol[i]) = symtab; + } } +} - return symtab; +/* Same as end_symtab, but for the case where we're adding more symbols + to an existing symtab that is known to contain only type information. + This is the case for DWARF4 Type Units. */ + +void +augment_type_symtab (struct objfile *objfile, struct symtab *primary_symtab) +{ + struct blockvector *blockvector = primary_symtab->blockvector; + int i; + + if (context_stack_depth > 0) + { + complaint (&symfile_complaints, + _("Context stack not empty in augment_type_symtab")); + context_stack_depth = 0; + } + if (pending_blocks != NULL) + complaint (&symfile_complaints, _("Blocks in a type symtab")); + if (pending_macros != NULL) + complaint (&symfile_complaints, _("Macro in a type symtab")); + if (have_line_numbers) + complaint (&symfile_complaints, + _("Line numbers recorded in a type symtab")); + + if (file_symbols != NULL) + { + struct block *block = BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK); + + /* First mark any symbols without a specified symtab as belonging + to the primary symtab. */ + set_missing_symtab (file_symbols, primary_symtab); + + dict_add_pending (BLOCK_DICT (block), file_symbols); + } + + if (global_symbols != NULL) + { + struct block *block = BLOCKVECTOR_BLOCK (blockvector, GLOBAL_BLOCK); + + /* First mark any symbols without a specified symtab as belonging + to the primary symtab. */ + set_missing_symtab (global_symbols, primary_symtab); + + dict_add_pending (BLOCK_DICT (block), global_symbols); + } + + reset_symtab_globals (); } /* Push a context block. Args are an identifying nesting level @@ -1223,14 +1428,12 @@ push_context (int desc, CORE_ADDR valu) new = &context_stack[context_stack_depth++]; new->depth = desc; new->locals = local_symbols; - 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; @@ -1251,7 +1454,7 @@ pop_context (void) /* Compute a small integer hash code for the given name. */ int -hashname (char *name) +hashname (const char *name) { return (hash(name,strlen(name)) % HASHSIZE); } @@ -1297,6 +1500,32 @@ merge_symbol_lists (struct pending **srclist, struct pending **targetlist) free_pendings = (*srclist); } + +/* Name of source file whose symbol data we are now processing. This + comes from a symbol of type N_SO for stabs. For Dwarf it comes + from the DW_AT_name attribute of a DW_TAG_compile_unit DIE. */ + +static char *last_source_file; + +/* See buildsym.h. */ + +void +set_last_source_file (const char *name) +{ + xfree (last_source_file); + last_source_file = name == NULL ? NULL : xstrdup (name); +} + +/* See buildsym.h. */ + +const char * +get_last_source_file (void) +{ + return last_source_file; +} + + + /* Initialize anything that needs initializing when starting to read a fresh piece of a symbol file, e.g. reading in the stuff corresponding to a psymtab. */ @@ -1309,6 +1538,7 @@ buildsym_init (void) global_symbols = NULL; pending_blocks = NULL; pending_macros = NULL; + using_directives = NULL; /* We shouldn't have any address map at this point. */ gdb_assert (! pending_addrmap); diff --git a/contrib/gdb-7/gdb/buildsym.h b/contrib/gdb-7/gdb/buildsym.h index 1604ef51fb..4bde17a44c 100644 --- a/contrib/gdb-7/gdb/buildsym.h +++ b/contrib/gdb-7/gdb/buildsym.h @@ -1,6 +1,5 @@ /* Build symbol tables in GDB's internal format. - Copyright (C) 1986-1993, 1995-2000, 2002-2003, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -37,6 +36,7 @@ struct addrmap; this technique. */ struct block; +struct pending_block; #ifndef EXTERN #define EXTERN extern @@ -45,12 +45,6 @@ struct block; #define HASHSIZE 127 /* Size of things hashed via hashname(). */ -/* Name of source file whose symbol data we are now processing. This - comes from a symbol of type N_SO for stabs. For Dwarf it comes - from the DW_AT_name attribute of a DW_TAG_compile_unit DIE. */ - -EXTERN char *last_source_file; - /* Core address of start of text of current source file. This too comes from the N_SO symbol. For Dwarf it typically comes from the DW_AT_low_pc attribute of a DW_TAG_compile_unit DIE. */ @@ -120,10 +114,6 @@ EXTERN struct pending *global_symbols; EXTERN struct pending *local_symbols; -/* func params local to lexical context */ - -EXTERN struct pending *param_symbols; - /* "using" directives local to lexical context. */ EXTERN struct using_direct *using_directives; @@ -137,10 +127,6 @@ struct context_stack struct pending *locals; - /* Pending func params at the time we entered */ - - struct pending *params; - /* Pending using directives at the time we entered. */ struct using_direct *using_directives; @@ -185,21 +171,6 @@ EXTERN int context_stack_size; EXTERN int within_function; -/* List of blocks already made (lexical contexts already closed). - This is used at the end to make the blockvector. */ - -struct pending_block - { - struct pending_block *next; - struct block *block; - }; - -/* Pointer to the head of a linked list of symbol blocks which have - already been finalized (lexical contexts already closed) and which - are just waiting to be built into a blockvector when finalizing the - associated symtab. */ - -EXTERN struct pending_block *pending_blocks; struct subfile_stack @@ -233,8 +204,6 @@ EXTERN int type_vector_length; #define INITIAL_TYPE_VECTOR_LENGTH 160 -extern void add_free_pendings (struct pending *list); - extern void add_symbol_to_list (struct symbol *symbol, struct pending **listhead); @@ -260,9 +229,26 @@ extern void push_subfile (void); extern char *pop_subfile (void); +extern struct block *end_symtab_get_static_block (CORE_ADDR end_addr, + struct objfile *objfile, + int expandable, + int required); + +extern struct symtab *end_symtab_from_static_block (struct block *static_block, + struct objfile *objfile, + int section, + int expandable); + extern struct symtab *end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section); +extern struct symtab *end_expandable_symtab (CORE_ADDR end_addr, + struct objfile *objfile, + int section); + +extern void augment_type_symtab (struct objfile *objfile, + struct symtab *primary_symtab); + /* Defined in stabsread.c. */ extern void scan_file_globals (struct objfile *objfile); @@ -277,19 +263,14 @@ extern struct context_stack *pop_context (void); extern void record_line (struct subfile *subfile, int line, CORE_ADDR pc); -extern void start_symtab (char *name, char *dirname, CORE_ADDR start_addr); - -extern int hashname (char *name); +extern void start_symtab (const char *name, const char *dirname, + CORE_ADDR start_addr); -extern void free_pending_blocks (void); +extern void restart_symtab (CORE_ADDR start_addr); -/* FIXME: Note that this is used only in buildsym.c and dstread.c, - which should be fixed to not need direct access to - record_pending_block. */ +extern int hashname (const char *name); -extern void record_pending_block (struct objfile *objfile, - struct block *block, - struct pending_block *opblock); +extern void free_pending_blocks (void); /* Record the name of the debug format in the current pending symbol table. FORMAT must be a string with a lifetime at least as long as @@ -306,6 +287,15 @@ extern void record_producer (const char *producer); extern void merge_symbol_lists (struct pending **srclist, struct pending **targetlist); +/* Set the name of the last source file. NAME is copied by this + function. */ + +extern void set_last_source_file (const char *name); + +/* Fetch the name of the last source file. */ + +extern const char *get_last_source_file (void); + /* The macro table for the compilation unit whose symbols we're currently reading. All the symtabs for this CU will point to this. */ diff --git a/contrib/gdb-7/gdb/c-exp.y b/contrib/gdb-7/gdb/c-exp.y index bdcae3310b..f6659d47fb 100644 --- a/contrib/gdb-7/gdb/c-exp.y +++ b/contrib/gdb-7/gdb/c-exp.y @@ -1,6 +1,5 @@ /* YACC parser for C expressions, for GDB. - Copyright (C) 1986, 1989-2000, 2003-2004, 2006-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -53,6 +52,9 @@ #include "dfp.h" #include "gdb_assert.h" #include "macroscope.h" +#include "objc-lang.h" +#include "typeprint.h" +#include "cp-abi.h" #define parse_type builtin_type (parse_gdbarch) @@ -103,6 +105,12 @@ #define yygindex c_yygindex #define yytable c_yytable #define yycheck c_yycheck +#define yyss c_yyss +#define yysslim c_yysslim +#define yyssp c_yyssp +#define yystacksize c_yystacksize +#define yyvs c_yyvs +#define yyvsp c_yyvsp #ifndef YYDEBUG #define YYDEBUG 1 /* Default to yydebug support */ @@ -149,26 +157,33 @@ void yyerror (char *); struct internalvar *ivar; struct stoken_vector svec; - struct type **tvec; + VEC (type_ptr) *tvec; int *ivec; + + struct type_stack *type_stack; + + struct objc_class_str class; } %{ /* YYSTYPE gets defined by %union */ static int parse_number (char *, int, int, YYSTYPE *); static struct stoken operator_stoken (const char *); +static void check_parameter_typelist (VEC (type_ptr) *); %} %type exp exp1 type_exp start variable qualified_name lcurly %type rcurly %type type typebase -%type nonempty_typelist +%type nonempty_typelist func_mod parameter_typelist /* %type block */ /* Fancy type parsing. */ -%type func_mod direct_abs_decl abs_decl %type ptype %type array_mod +%type conversion_type_id + +%type ptr_operator_ts abs_decl direct_abs_decl %token INT %token FLOAT @@ -183,16 +198,24 @@ static struct stoken operator_stoken (const char *); nonterminal "name", which matches either NAME or TYPENAME. */ %token STRING +%token NSSTRING /* ObjC Foundation "NSString" literal */ +%token SELECTOR /* ObjC "@selector" pseudo-operator */ %token CHAR %token NAME /* BLOCKNAME defined below to give it higher precedence. */ %token UNKNOWN_CPP_NAME %token COMPLETE %token TYPENAME +%token CLASSNAME /* ObjC Class name */ %type name %type string_exp %type name_not_typename %type typename + /* This is like a '[' token, but is only generated when parsing + Objective C. This lets us reuse the same parser without + erroneously parsing ObjC-specific expressions in C. */ +%token OBJC_LBRAC + /* A NAME_OR_INT is a symbol which is not known in the symbol table, but which would parse as a valid number in the current input radix. E.g. "c" when input_radix==16. Depending on the parse, it will be @@ -208,6 +231,8 @@ static struct stoken operator_stoken (const char *); %type operator %token REINTERPRET_CAST DYNAMIC_CAST STATIC_CAST CONST_CAST %token ENTRY +%token TYPEOF +%token DECLTYPE /* Special type cases, put in to allow the parser to distinguish different legal basetypes. */ @@ -238,12 +263,14 @@ static struct stoken operator_stoken (const char *); %left '+' '-' %left '*' '/' '%' %right UNARY INCREMENT DECREMENT -%right ARROW ARROW_STAR '.' DOT_STAR '[' '(' +%right ARROW ARROW_STAR '.' DOT_STAR '[' OBJC_LBRAC '(' %token BLOCKNAME %token FILENAME %type block %left COLONCOLON +%token DOTDOTDOT + %% @@ -255,6 +282,20 @@ type_exp: type { write_exp_elt_opcode(OP_TYPE); write_exp_elt_type($1); write_exp_elt_opcode(OP_TYPE);} + | TYPEOF '(' exp ')' + { + write_exp_elt_opcode (OP_TYPEOF); + } + | TYPEOF '(' type ')' + { + write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type ($3); + write_exp_elt_opcode (OP_TYPE); + } + | DECLTYPE '(' exp ')' + { + write_exp_elt_opcode (OP_DECLTYPE); + } ; /* Expressions, including the comma operator. */ @@ -382,6 +423,78 @@ exp : exp '[' exp1 ']' { write_exp_elt_opcode (BINOP_SUBSCRIPT); } ; +exp : exp OBJC_LBRAC exp1 ']' + { write_exp_elt_opcode (BINOP_SUBSCRIPT); } + ; + +/* + * The rules below parse ObjC message calls of the form: + * '[' target selector {':' argument}* ']' + */ + +exp : OBJC_LBRAC TYPENAME + { + CORE_ADDR class; + + class = lookup_objc_class (parse_gdbarch, + copy_name ($2.stoken)); + if (class == 0) + error (_("%s is not an ObjC Class"), + copy_name ($2.stoken)); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (parse_type->builtin_int); + write_exp_elt_longcst ((LONGEST) class); + write_exp_elt_opcode (OP_LONG); + start_msglist(); + } + msglist ']' + { write_exp_elt_opcode (OP_OBJC_MSGCALL); + end_msglist(); + write_exp_elt_opcode (OP_OBJC_MSGCALL); + } + ; + +exp : OBJC_LBRAC CLASSNAME + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (parse_type->builtin_int); + write_exp_elt_longcst ((LONGEST) $2.class); + write_exp_elt_opcode (OP_LONG); + start_msglist(); + } + msglist ']' + { write_exp_elt_opcode (OP_OBJC_MSGCALL); + end_msglist(); + write_exp_elt_opcode (OP_OBJC_MSGCALL); + } + ; + +exp : OBJC_LBRAC exp + { start_msglist(); } + msglist ']' + { write_exp_elt_opcode (OP_OBJC_MSGCALL); + end_msglist(); + write_exp_elt_opcode (OP_OBJC_MSGCALL); + } + ; + +msglist : name + { add_msglist(&$1, 0); } + | msgarglist + ; + +msgarglist : msgarg + | msgarglist msgarg + ; + +msgarg : name ':' exp + { add_msglist(&$1, 1); } + | ':' exp /* Unnamed arg. */ + { add_msglist(0, 1); } + | ',' exp /* Variable number of args. */ + { add_msglist(0, 0); } + ; + exp : exp '(' /* This is to save the value of arglist_len being accumulated by an outer function call. */ @@ -430,15 +543,21 @@ arglist : arglist ',' exp %prec ABOVE_COMMA { arglist_len++; } ; -exp : exp '(' nonempty_typelist ')' const_or_volatile +exp : exp '(' parameter_typelist ')' const_or_volatile { int i; + VEC (type_ptr) *type_list = $3; + struct type *type_elt; + LONGEST len = VEC_length (type_ptr, type_list); + 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_longcst (len); + for (i = 0; + VEC_iterate (type_ptr, type_list, i, type_elt); + ++i) + write_exp_elt_type (type_elt); + write_exp_elt_longcst(len); write_exp_elt_opcode (TYPE_INSTANCE); - free ($3); + VEC_free (type_ptr, type_list); } ; @@ -452,16 +571,12 @@ exp : lcurly arglist rcurly %prec ARROW write_exp_elt_opcode (OP_ARRAY); } ; -exp : lcurly type rcurly exp %prec UNARY - { write_exp_elt_opcode (UNOP_MEMVAL); - write_exp_elt_type ($2); - write_exp_elt_opcode (UNOP_MEMVAL); } +exp : lcurly type_exp rcurly exp %prec UNARY + { write_exp_elt_opcode (UNOP_MEMVAL_TYPE); } ; -exp : '(' type ')' exp %prec UNARY - { write_exp_elt_opcode (UNOP_CAST); - write_exp_elt_type ($2); - write_exp_elt_opcode (UNOP_CAST); } +exp : '(' type_exp ')' exp %prec UNARY + { write_exp_elt_opcode (UNOP_CAST_TYPE); } ; exp : '(' exp1 ')' @@ -610,6 +725,13 @@ exp : VARIABLE } ; +exp : SELECTOR '(' name ')' + { + write_exp_elt_opcode (OP_OBJC_SELECTOR); + write_exp_string ($3); + write_exp_elt_opcode (OP_OBJC_SELECTOR); } + ; + exp : SIZEOF '(' type ')' %prec UNARY { write_exp_elt_opcode (OP_LONG); write_exp_elt_type (lookup_signed_typename @@ -620,30 +742,22 @@ exp : SIZEOF '(' type ')' %prec UNARY write_exp_elt_opcode (OP_LONG); } ; -exp : REINTERPRET_CAST '<' type '>' '(' exp ')' %prec UNARY - { write_exp_elt_opcode (UNOP_REINTERPRET_CAST); - write_exp_elt_type ($3); - write_exp_elt_opcode (UNOP_REINTERPRET_CAST); } +exp : REINTERPRET_CAST '<' type_exp '>' '(' exp ')' %prec UNARY + { write_exp_elt_opcode (UNOP_REINTERPRET_CAST); } ; -exp : STATIC_CAST '<' type '>' '(' exp ')' %prec UNARY - { write_exp_elt_opcode (UNOP_CAST); - write_exp_elt_type ($3); - write_exp_elt_opcode (UNOP_CAST); } +exp : STATIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY + { write_exp_elt_opcode (UNOP_CAST_TYPE); } ; -exp : DYNAMIC_CAST '<' type '>' '(' exp ')' %prec UNARY - { write_exp_elt_opcode (UNOP_DYNAMIC_CAST); - write_exp_elt_type ($3); - write_exp_elt_opcode (UNOP_DYNAMIC_CAST); } +exp : DYNAMIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY + { write_exp_elt_opcode (UNOP_DYNAMIC_CAST); } ; -exp : CONST_CAST '<' type '>' '(' exp ')' %prec UNARY +exp : CONST_CAST '<' type_exp '>' '(' exp ')' %prec UNARY { /* We could do more error checking here, but it doesn't seem worthwhile. */ - write_exp_elt_opcode (UNOP_CAST); - write_exp_elt_type ($3); - write_exp_elt_opcode (UNOP_CAST); } + write_exp_elt_opcode (UNOP_CAST_TYPE); } ; string_exp: @@ -715,6 +829,14 @@ exp : string_exp } ; +exp : NSSTRING /* ObjC NextStep NSString constant + * of the form '@' '"' string '"'. + */ + { write_exp_elt_opcode (OP_OBJC_NSSTRING); + write_exp_string ($1); + write_exp_elt_opcode (OP_OBJC_NSSTRING); } + ; + /* C++. */ exp : TRUEKEYWORD { write_exp_elt_opcode (OP_LONG); @@ -749,7 +871,7 @@ block : BLOCKNAME block : block COLONCOLON name { struct symbol *tem = lookup_symbol (copy_name ($3), $1, - VAR_DOMAIN, (int *) NULL); + VAR_DOMAIN, NULL); if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) error (_("No function \"%s\" in specified context."), copy_name ($3)); @@ -774,10 +896,17 @@ variable: name_not_typename ENTRY variable: block COLONCOLON name { struct symbol *sym; sym = lookup_symbol (copy_name ($3), $1, - VAR_DOMAIN, (int *) NULL); + VAR_DOMAIN, NULL); if (sym == 0) error (_("No symbol \"%s\" in specified context."), copy_name ($3)); + if (symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 + || contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } write_exp_elt_opcode (OP_VAR_VALUE); /* block_found is set by lookup_symbol. */ @@ -794,7 +923,7 @@ qualified_name: TYPENAME COLONCOLON name && TYPE_CODE (type) != TYPE_CODE_UNION && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) error (_("`%s' is not defined as an aggregate type."), - TYPE_NAME (type)); + TYPE_SAFE_NAME (type)); write_exp_elt_opcode (OP_SCOPE); write_exp_elt_type (type); @@ -810,7 +939,7 @@ qualified_name: TYPENAME COLONCOLON name && TYPE_CODE (type) != TYPE_CODE_UNION && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) error (_("`%s' is not defined as an aggregate type."), - TYPE_NAME (type)); + TYPE_SAFE_NAME (type)); tmp_token.ptr = (char*) alloca ($4.length + 2); tmp_token.length = $4.length + 1; @@ -830,7 +959,7 @@ qualified_name: TYPENAME COLONCOLON name char *copy = copy_name ($3); error (_("No type \"%s\" within class " "or namespace \"%s\"."), - copy, TYPE_NAME ($1.type)); + copy, TYPE_SAFE_NAME ($1.type)); } ; @@ -843,7 +972,7 @@ variable: qualified_name sym = lookup_symbol (name, (const struct block *) NULL, - VAR_DOMAIN, (int *) NULL); + VAR_DOMAIN, NULL); if (sym) { write_exp_elt_opcode (OP_VAR_VALUE); @@ -918,9 +1047,7 @@ variable: name_not_typename ; space_identifier : '@' NAME - { push_type_address_space (copy_name ($2.stoken)); - push_type (tp_space_identifier); - } + { insert_type_address_space (copy_name ($2.stoken)); } ; const_or_volatile: const_or_volatile_noopt @@ -939,14 +1066,31 @@ const_or_volatile_or_space_identifier: | ; -abs_decl: '*' - { push_type (tp_pointer); $$ = 0; } - | '*' abs_decl - { push_type (tp_pointer); $$ = $2; } +ptr_operator: + ptr_operator '*' + { insert_type (tp_pointer); } + const_or_volatile_or_space_identifier + | '*' + { insert_type (tp_pointer); } + const_or_volatile_or_space_identifier | '&' - { push_type (tp_reference); $$ = 0; } - | '&' abs_decl - { push_type (tp_reference); $$ = $2; } + { insert_type (tp_reference); } + | '&' ptr_operator + { insert_type (tp_reference); } + ; + +ptr_operator_ts: ptr_operator + { + $$ = get_type_stack (); + /* This cleanup is eventually run by + c_parse. */ + make_cleanup (type_stack_cleanup, $$); + } + ; + +abs_decl: ptr_operator_ts direct_abs_decl + { $$ = append_type_stack ($2, $1); } + | ptr_operator_ts | direct_abs_decl ; @@ -954,32 +1098,45 @@ direct_abs_decl: '(' abs_decl ')' { $$ = $2; } | direct_abs_decl array_mod { + push_type_stack ($1); push_type_int ($2); push_type (tp_array); + $$ = get_type_stack (); } | array_mod { push_type_int ($1); push_type (tp_array); - $$ = 0; + $$ = get_type_stack (); } | direct_abs_decl func_mod - { push_type (tp_function); } + { + push_type_stack ($1); + push_typelist ($2); + $$ = get_type_stack (); + } | func_mod - { push_type (tp_function); } + { + push_typelist ($1); + $$ = get_type_stack (); + } ; array_mod: '[' ']' { $$ = -1; } + | OBJC_LBRAC ']' + { $$ = -1; } | '[' INT ']' { $$ = $2.val; } + | OBJC_LBRAC INT ']' + { $$ = $2.val; } ; func_mod: '(' ')' - { $$ = 0; } - | '(' nonempty_typelist ')' - { free ($2); $$ = 0; } + { $$ = NULL; } + | '(' parameter_typelist ')' + { $$ = $2; } ; /* We used to try to recognize pointer to member types here, but @@ -1111,15 +1268,59 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ | STRUCT name { $$ = lookup_struct (copy_name ($2), expression_context_block); } + | STRUCT COMPLETE + { + mark_completion_tag (TYPE_CODE_STRUCT, "", 0); + $$ = NULL; + } + | STRUCT name COMPLETE + { + mark_completion_tag (TYPE_CODE_STRUCT, $2.ptr, + $2.length); + $$ = NULL; + } | CLASS name { $$ = lookup_struct (copy_name ($2), expression_context_block); } + | CLASS COMPLETE + { + mark_completion_tag (TYPE_CODE_CLASS, "", 0); + $$ = NULL; + } + | CLASS name COMPLETE + { + mark_completion_tag (TYPE_CODE_CLASS, $2.ptr, + $2.length); + $$ = NULL; + } | UNION name { $$ = lookup_union (copy_name ($2), expression_context_block); } + | UNION COMPLETE + { + mark_completion_tag (TYPE_CODE_UNION, "", 0); + $$ = NULL; + } + | UNION name COMPLETE + { + mark_completion_tag (TYPE_CODE_UNION, $2.ptr, + $2.length); + $$ = NULL; + } | ENUM name { $$ = lookup_enum (copy_name ($2), expression_context_block); } + | ENUM COMPLETE + { + mark_completion_tag (TYPE_CODE_ENUM, "", 0); + $$ = NULL; + } + | ENUM name COMPLETE + { + mark_completion_tag (TYPE_CODE_ENUM, $2.ptr, + $2.length); + $$ = NULL; + } | UNSIGNED typename { $$ = lookup_unsigned_typename (parse_language, parse_gdbarch, @@ -1176,36 +1377,59 @@ typename: TYPENAME } ; +parameter_typelist: + nonempty_typelist + { check_parameter_typelist ($1); } + | nonempty_typelist ',' DOTDOTDOT + { + VEC_safe_push (type_ptr, $1, NULL); + check_parameter_typelist ($1); + $$ = $1; + } + ; + nonempty_typelist : type - { $$ = (struct type **) malloc (sizeof (struct type *) * 2); - $$[0] = 1; /* Number of types in vector */ - $$[1] = $1; + { + VEC (type_ptr) *typelist = NULL; + VEC_safe_push (type_ptr, typelist, $1); + $$ = typelist; } | nonempty_typelist ',' type - { int len = sizeof (struct type *) * (++($1[0]) + 1); - $$ = (struct type **) realloc ((char *) $1, len); - $$[$$[0]] = $3; + { + VEC_safe_push (type_ptr, $1, $3); + $$ = $1; } ; ptype : typebase - | ptype const_or_volatile_or_space_identifier abs_decl const_or_volatile_or_space_identifier + | ptype abs_decl + { + push_type_stack ($2); + $$ = follow_types ($1); + } + ; + +conversion_type_id: typebase conversion_declarator { $$ = follow_types ($1); } ; +conversion_declarator: /* Nothing. */ + | ptr_operator conversion_declarator + ; + const_and_volatile: CONST_KEYWORD VOLATILE_KEYWORD | VOLATILE_KEYWORD CONST_KEYWORD ; const_or_volatile_noopt: const_and_volatile - { push_type (tp_const); - push_type (tp_volatile); + { insert_type (tp_const); + insert_type (tp_volatile); } | CONST_KEYWORD - { push_type (tp_const); } + { insert_type (tp_const); } | VOLATILE_KEYWORD - { push_type (tp_volatile); } + { insert_type (tp_volatile); } ; operator: OPERATOR NEW @@ -1216,6 +1440,10 @@ operator: OPERATOR NEW { $$ = operator_stoken (" new[]"); } | OPERATOR DELETE '[' ']' { $$ = operator_stoken (" delete[]"); } + | OPERATOR NEW OBJC_LBRAC ']' + { $$ = operator_stoken (" new[]"); } + | OPERATOR DELETE OBJC_LBRAC ']' + { $$ = operator_stoken (" delete[]"); } | OPERATOR '+' { $$ = operator_stoken ("+"); } | OPERATOR '-' @@ -1312,12 +1540,15 @@ operator: OPERATOR NEW { $$ = operator_stoken ("()"); } | OPERATOR '[' ']' { $$ = operator_stoken ("[]"); } - | OPERATOR ptype + | OPERATOR OBJC_LBRAC ']' + { $$ = operator_stoken ("[]"); } + | OPERATOR conversion_type_id { char *name; long length; struct ui_file *buf = mem_fileopen (); - c_print_type ($2, NULL, buf, -1, 0); + c_print_type ($2, NULL, buf, -1, 0, + &type_print_raw_options); name = ui_file_xstrdup (buf, &length); ui_file_delete (buf); $$ = operator_stoken (name); @@ -1346,11 +1577,15 @@ name_not_typename : NAME */ | operator { + struct field_of_this_result is_a_field_of_this; + $$.stoken = $1; $$.sym = lookup_symbol ($1.ptr, expression_context_block, VAR_DOMAIN, - &$$.is_a_field_of_this); + &is_a_field_of_this); + $$.is_a_field_of_this + = is_a_field_of_this.type != NULL; } | UNKNOWN_CPP_NAME ; @@ -1374,6 +1609,37 @@ operator_stoken (const char *op) return st; }; +/* Validate a parameter typelist. */ + +static void +check_parameter_typelist (VEC (type_ptr) *params) +{ + struct type *type; + int ix; + + for (ix = 0; VEC_iterate (type_ptr, params, ix, type); ++ix) + { + if (type != NULL && TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID) + { + if (ix == 0) + { + if (VEC_length (type_ptr, params) == 1) + { + /* Ok. */ + break; + } + VEC_free (type_ptr, params); + error (_("parameter types following 'void'")); + } + else + { + VEC_free (type_ptr, params); + error (_("'void' invalid as parameter type")); + } + } + } +} + /* Take care of parsing a number (anything that starts with a digit). Set yylval and return the token type; update lexptr. LEN is the number of characters in it. */ @@ -1406,9 +1672,6 @@ parse_number (char *p, int len, int parsed_float, YYSTYPE *putithere) if (parsed_float) { - const char *suffix; - int suffix_len; - /* If it ends at "df", "dd" or "dl", take it as type of decimal floating point. Return DECFLOAT. */ @@ -1792,6 +2055,7 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value, { int quote; enum c_string_type type; + int is_objc = 0; /* Build the gdb internal form of the input string in tempbuf. Note that the buffer is null byte terminated *only* for the @@ -1824,6 +2088,13 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value, type = C_STRING_32; ++tokptr; } + else if (*tokptr == '@') + { + /* An Objective C string. */ + is_objc = 1; + type = C_STRING; + ++tokptr; + } else type = C_STRING; @@ -1871,22 +2142,38 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value, *outptr = tokptr; - return quote == '"' ? STRING : CHAR; + return quote == '"' ? (is_objc ? NSSTRING : STRING) : CHAR; } +/* This is used to associate some attributes with a token. */ + +enum token_flags +{ + /* If this bit is set, the token is C++-only. */ + + FLAG_CXX = 1, + + /* If this bit is set, the token is conditional: if there is a + symbol of the same name, then the token is a symbol; otherwise, + the token is a keyword. */ + + FLAG_SHADOW = 2 +}; + struct token { char *operator; int token; enum exp_opcode opcode; - int cxx_only; + enum token_flags flags; }; static const struct token tokentab3[] = { {">>=", ASSIGN_MODIFY, BINOP_RSH, 0}, {"<<=", ASSIGN_MODIFY, BINOP_LSH, 0}, - {"->*", ARROW_STAR, BINOP_END, 1} + {"->*", ARROW_STAR, BINOP_END, FLAG_CXX}, + {"...", DOTDOTDOT, BINOP_END, 0} }; static const struct token tokentab2[] = @@ -1913,48 +2200,54 @@ static const struct token tokentab2[] = {"!=", NOTEQUAL, BINOP_END, 0}, {"<=", LEQ, BINOP_END, 0}, {">=", GEQ, BINOP_END, 0}, - {".*", DOT_STAR, BINOP_END, 1} + {".*", DOT_STAR, BINOP_END, FLAG_CXX} }; /* Identifier-like tokens. */ static const struct token ident_tokens[] = { {"unsigned", UNSIGNED, OP_NULL, 0}, - {"template", TEMPLATE, OP_NULL, 1}, + {"template", TEMPLATE, OP_NULL, FLAG_CXX}, {"volatile", VOLATILE_KEYWORD, OP_NULL, 0}, {"struct", STRUCT, OP_NULL, 0}, {"signed", SIGNED_KEYWORD, OP_NULL, 0}, {"sizeof", SIZEOF, OP_NULL, 0}, {"double", DOUBLE_KEYWORD, OP_NULL, 0}, - {"false", FALSEKEYWORD, OP_NULL, 1}, - {"class", CLASS, OP_NULL, 1}, + {"false", FALSEKEYWORD, OP_NULL, FLAG_CXX}, + {"class", CLASS, OP_NULL, FLAG_CXX}, {"union", UNION, OP_NULL, 0}, {"short", SHORT, OP_NULL, 0}, {"const", CONST_KEYWORD, OP_NULL, 0}, {"enum", ENUM, OP_NULL, 0}, {"long", LONG, OP_NULL, 0}, - {"true", TRUEKEYWORD, OP_NULL, 1}, + {"true", TRUEKEYWORD, OP_NULL, FLAG_CXX}, {"int", INT_KEYWORD, OP_NULL, 0}, - {"new", NEW, OP_NULL, 1}, - {"delete", DELETE, OP_NULL, 1}, - {"operator", OPERATOR, OP_NULL, 1}, - - {"and", ANDAND, BINOP_END, 1}, - {"and_eq", ASSIGN_MODIFY, BINOP_BITWISE_AND, 1}, - {"bitand", '&', OP_NULL, 1}, - {"bitor", '|', OP_NULL, 1}, - {"compl", '~', OP_NULL, 1}, - {"not", '!', OP_NULL, 1}, - {"not_eq", NOTEQUAL, BINOP_END, 1}, - {"or", OROR, BINOP_END, 1}, - {"or_eq", ASSIGN_MODIFY, BINOP_BITWISE_IOR, 1}, - {"xor", '^', OP_NULL, 1}, - {"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, 1}, - - {"const_cast", CONST_CAST, OP_NULL, 1 }, - {"dynamic_cast", DYNAMIC_CAST, OP_NULL, 1 }, - {"static_cast", STATIC_CAST, OP_NULL, 1 }, - {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, 1 } + {"new", NEW, OP_NULL, FLAG_CXX}, + {"delete", DELETE, OP_NULL, FLAG_CXX}, + {"operator", OPERATOR, OP_NULL, FLAG_CXX}, + + {"and", ANDAND, BINOP_END, FLAG_CXX}, + {"and_eq", ASSIGN_MODIFY, BINOP_BITWISE_AND, FLAG_CXX}, + {"bitand", '&', OP_NULL, FLAG_CXX}, + {"bitor", '|', OP_NULL, FLAG_CXX}, + {"compl", '~', OP_NULL, FLAG_CXX}, + {"not", '!', OP_NULL, FLAG_CXX}, + {"not_eq", NOTEQUAL, BINOP_END, FLAG_CXX}, + {"or", OROR, BINOP_END, FLAG_CXX}, + {"or_eq", ASSIGN_MODIFY, BINOP_BITWISE_IOR, FLAG_CXX}, + {"xor", '^', OP_NULL, FLAG_CXX}, + {"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, FLAG_CXX}, + + {"const_cast", CONST_CAST, OP_NULL, FLAG_CXX }, + {"dynamic_cast", DYNAMIC_CAST, OP_NULL, FLAG_CXX }, + {"static_cast", STATIC_CAST, OP_NULL, FLAG_CXX }, + {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, FLAG_CXX }, + + {"__typeof__", TYPEOF, OP_TYPEOF, 0 }, + {"__typeof", TYPEOF, OP_TYPEOF, 0 }, + {"typeof", TYPEOF, OP_TYPEOF, FLAG_SHADOW }, + {"__decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX }, + {"decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX | FLAG_SHADOW } }; /* When we find that lexptr (the global var defined in parse.c) is @@ -2090,7 +2383,7 @@ lex_one_token (void) for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) if (strncmp (tokstart, tokentab3[i].operator, 3) == 0) { - if (tokentab3[i].cxx_only + if ((tokentab3[i].flags & FLAG_CXX) != 0 && parse_language->la_language != language_cplus) break; @@ -2103,13 +2396,13 @@ lex_one_token (void) for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) if (strncmp (tokstart, tokentab2[i].operator, 2) == 0) { - if (tokentab2[i].cxx_only + if ((tokentab2[i].flags & FLAG_CXX) != 0 && parse_language->la_language != language_cplus) break; lexptr += 2; yylval.opcode = tokentab2[i].opcode; - if (in_parse_field && tokentab2[i].token == ARROW) + if (parse_completion && tokentab2[i].token == ARROW) last_was_structop = 1; return tokentab2[i].token; } @@ -2148,6 +2441,8 @@ lex_one_token (void) case '(': paren_depth++; lexptr++; + if (parse_language->la_language == language_objc && c == '[') + return OBJC_LBRAC; return c; case ']': @@ -2170,7 +2465,7 @@ lex_one_token (void) /* Might be a floating point number. */ if (lexptr[1] < '0' || lexptr[1] > '9') { - if (in_parse_field) + if (parse_completion) last_was_structop = 1; goto symbol; /* Nope, must be a symbol. */ } @@ -2244,6 +2539,20 @@ lex_one_token (void) char *p = &tokstart[1]; size_t len = strlen ("entry"); + if (parse_language->la_language == language_objc) + { + size_t len = strlen ("selector"); + + if (strncmp (p, "selector", len) == 0 + && (p[len] == '\0' || isspace (p[len]))) + { + lexptr = p + len; + return SELECTOR; + } + else if (*p == '"') + goto parse_string; + } + while (isspace (*p)) p++; if (strncmp (p, "entry", len) == 0 && !isalnum (p[len]) @@ -2283,6 +2592,8 @@ lex_one_token (void) /* Fall through. */ case '\'': case '"': + + parse_string: { int host_len; int result = parse_string_or_char (tokstart, &lexptr, &yylval.tsval, @@ -2377,10 +2688,26 @@ lex_one_token (void) for (i = 0; i < sizeof ident_tokens / sizeof ident_tokens[0]; i++) if (strcmp (copy, ident_tokens[i].operator) == 0) { - if (ident_tokens[i].cxx_only + if ((ident_tokens[i].flags & FLAG_CXX) != 0 && parse_language->la_language != language_cplus) break; + if ((ident_tokens[i].flags & FLAG_SHADOW) != 0) + { + struct field_of_this_result is_a_field_of_this; + + if (lookup_symbol (copy, expression_context_block, + VAR_DOMAIN, + (parse_language->la_language == language_cplus + ? &is_a_field_of_this + : NULL)) + != NULL) + { + /* The keyword is shadowed. */ + break; + } + } + /* It is ok to always set this, even though we don't always strictly need to. */ yylval.opcode = ident_tokens[i].opcode; @@ -2390,8 +2717,12 @@ lex_one_token (void) if (*tokstart == '$') return VARIABLE; - if (in_parse_field && *lexptr == '\0') + if (parse_completion && *lexptr == '\0') saw_name_at_eof = 1; + + yylval.ssym.stoken = yylval.sval; + yylval.ssym.sym = NULL; + yylval.ssym.is_a_field_of_this = 0; return NAME; } @@ -2420,22 +2751,26 @@ static struct obstack name_obstack; in which lookups start; this can be NULL to mean the global scope. */ static int -classify_name (struct block *block) +classify_name (const struct block *block) { struct symbol *sym; char *copy; - int is_a_field_of_this = 0; + struct field_of_this_result is_a_field_of_this; copy = copy_name (yylval.sval); + /* Initialize this in case we *don't* use it in this call; that way + we can refer to it unconditionally below. */ + memset (&is_a_field_of_this, 0, sizeof (is_a_field_of_this)); + sym = lookup_symbol (copy, block, VAR_DOMAIN, - parse_language->la_language == language_cplus - ? &is_a_field_of_this : (int *) NULL); + parse_language->la_name_of_this + ? &is_a_field_of_this : NULL); if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) { yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; + yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL; return BLOCKNAME; } else if (!sym) @@ -2449,6 +2784,26 @@ classify_name (struct block *block) yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK); return FILENAME; } + + /* If we found a field of 'this', we might have erroneously + found a constructor where we wanted a type name. Handle this + case by noticing that we found a constructor and then look up + the type tag instead. */ + if (is_a_field_of_this.type != NULL + && is_a_field_of_this.fn_field != NULL + && TYPE_FN_FIELD_CONSTRUCTOR (is_a_field_of_this.fn_field->fn_fields, + 0)) + { + struct field_of_this_result inner_is_a_field_of_this; + + sym = lookup_symbol (copy, block, STRUCT_DOMAIN, + &inner_is_a_field_of_this); + if (sym != NULL) + { + yylval.tsym.type = SYMBOL_TYPE (sym); + return TYPENAME; + } + } } if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) @@ -2463,6 +2818,20 @@ classify_name (struct block *block) if (yylval.tsym.type != NULL) return TYPENAME; + /* See if it's an ObjC classname. */ + if (parse_language->la_language == language_objc && !sym) + { + CORE_ADDR Class = lookup_objc_class (parse_gdbarch, copy); + if (Class) + { + yylval.class.class = Class; + sym = lookup_struct_typedef (copy, expression_context_block, 1); + if (sym) + yylval.class.type = SYMBOL_TYPE (sym); + return CLASSNAME; + } + } + /* Input names that aren't symbols but ARE valid hex numbers, when the input radix permits them, can be names or numbers depending on the parse. Note we support radixes > 16 here. */ @@ -2475,18 +2844,18 @@ classify_name (struct block *block) if (hextype == INT) { yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; + yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL; return NAME_OR_INT; } } /* Any other kind of symbol */ yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; + yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL; if (sym == NULL && parse_language->la_language == language_cplus - && !is_a_field_of_this + && is_a_field_of_this.type == NULL && !lookup_minimal_symbol (copy, NULL, NULL)) return UNKNOWN_CPP_NAME; @@ -2494,35 +2863,43 @@ classify_name (struct block *block) } /* Like classify_name, but used by the inner loop of the lexer, when a - name might have already been seen. FIRST_NAME is true if the token - in `yylval' is the first component of a name, false otherwise. If - this function returns NAME, it might not have updated `yylval'. - This is ok because the caller only cares about TYPENAME. */ + name might have already been seen. CONTEXT is the context type, or + NULL if this is the first component of a name. */ + static int -classify_inner_name (struct block *block, int first_name) +classify_inner_name (const struct block *block, struct type *context) { - struct type *type, *new_type; + struct type *type; char *copy; - if (first_name) + if (context == NULL) return classify_name (block); - type = check_typedef (yylval.tsym.type); + type = check_typedef (context); if (TYPE_CODE (type) != TYPE_CODE_STRUCT && TYPE_CODE (type) != TYPE_CODE_UNION && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) - /* We know the caller won't expect us to update yylval. */ - return NAME; + return ERROR; - copy = copy_name (yylval.tsym.stoken); - new_type = cp_lookup_nested_type (yylval.tsym.type, copy, block); + copy = copy_name (yylval.ssym.stoken); + yylval.ssym.sym = cp_lookup_nested_symbol (type, copy, block); + if (yylval.ssym.sym == NULL) + return ERROR; - if (new_type == NULL) - /* We know the caller won't expect us to update yylval. */ - return NAME; + switch (SYMBOL_CLASS (yylval.ssym.sym)) + { + case LOC_BLOCK: + case LOC_LABEL: + return ERROR; + + case LOC_TYPEDEF: + yylval.tsym.type = SYMBOL_TYPE (yylval.ssym.sym);; + return TYPENAME; - yylval.tsym.type = new_type; - return TYPENAME; + default: + return NAME; + } + internal_error (__FILE__, __LINE__, _("not reached")); } /* The outer level of a two-level lexer. This calls the inner lexer @@ -2541,6 +2918,7 @@ yylex (void) { token_and_value current; int first_was_coloncolon, last_was_coloncolon, first_iter; + struct type *context_type = NULL; if (popping && !VEC_empty (token_and_value, token_fifo)) { @@ -2562,7 +2940,10 @@ yylex (void) last_was_coloncolon = first_was_coloncolon; obstack_free (&name_obstack, obstack_base (&name_obstack)); if (!last_was_coloncolon) - obstack_grow (&name_obstack, yylval.sval.ptr, yylval.sval.length); + { + obstack_grow (&name_obstack, yylval.sval.ptr, yylval.sval.length); + context_type = yylval.tsym.type; + } current.value = yylval; first_iter = 1; while (1) @@ -2579,10 +2960,10 @@ yylex (void) classification = classify_inner_name (first_was_coloncolon ? NULL : expression_context_block, - first_iter); + context_type); /* We keep going until we either run out of names, or until we have a qualified name which is not a type. */ - if (classification != TYPENAME) + if (classification != TYPENAME && classification != NAME) { /* Push the final component and leave the loop. */ VEC_safe_push (token_and_value, token_fifo, &next); @@ -2590,7 +2971,7 @@ yylex (void) } /* Update the partial name we are constructing. */ - if (!first_iter) + if (context_type != NULL) { /* We don't want to put a leading "::" into the name. */ obstack_grow_str (&name_obstack, "::"); @@ -2604,6 +2985,11 @@ yylex (void) current.token = classification; last_was_coloncolon = 0; + + if (classification == NAME) + break; + + context_type = yylval.tsym.type; } else if (next.token == COLONCOLON && !last_was_coloncolon) last_was_coloncolon = 1; diff --git a/contrib/gdb-7/gdb/c-lang.c b/contrib/gdb-7/gdb/c-lang.c index c4d841fa9d..1c1d60b4f5 100644 --- a/contrib/gdb-7/gdb/c-lang.c +++ b/contrib/gdb-7/gdb/c-lang.c @@ -1,7 +1,6 @@ /* C language support routines for GDB, the GNU debugger. - Copyright (C) 1992-1996, 1998-2000, 2002-2005, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -87,7 +86,7 @@ classify_type (struct type *elttype, struct gdbarch *gdbarch, that would do the wrong thing. */ while (elttype) { - char *name = TYPE_NAME (elttype); + const char *name = TYPE_NAME (elttype); if (TYPE_CODE (elttype) == TYPE_CODE_CHAR || !name) { @@ -197,18 +196,6 @@ c_printstr (struct ui_file *stream, struct type *type, const char *type_encoding; const char *encoding; - enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type)); - 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; - struct wchar_iterator *iter; - int finished = 0; - int need_escape = 0; - str_type = (classify_type (type, get_type_arch (type), &type_encoding) & ~C_CHAR); switch (str_type) @@ -257,7 +244,6 @@ c_get_string (struct value *value, gdb_byte **buffer, int req_length = *length; enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type)); - enum c_string_type kind; if (element_type == NULL) goto error; @@ -286,9 +272,7 @@ c_get_string (struct value *value, gdb_byte **buffer, if (! c_textual_element_type (element_type, 0)) goto error; - kind = classify_type (element_type, - get_type_arch (element_type), - charset); + classify_type (element_type, get_type_arch (element_type), charset); width = TYPE_LENGTH (element_type); /* If the string lives in GDB's memory instead of the inferior's, @@ -552,7 +536,7 @@ parse_one_string (struct obstack *output, char *data, int len, /* If we saw a run of characters, convert them all. */ if (p > data) convert_between_encodings (host_charset (), dest_charset, - data, p - data, 1, + (gdb_byte *) data, p - data, 1, output, translit_none); /* If we saw an escape, convert it. */ if (p < limit) @@ -748,6 +732,7 @@ const struct op_print c_op_print_tab[] = {"/", BINOP_DIV, PREC_MUL, 0}, {"%", BINOP_REM, PREC_MUL, 0}, {"@", BINOP_REPEAT, PREC_REPEAT, 0}, + {"+", UNOP_PLUS, PREC_PREFIX, 0}, {"-", UNOP_NEG, PREC_PREFIX, 0}, {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0}, @@ -832,7 +817,6 @@ const struct language_defn c_language_defn = "c", /* Language name */ language_c, range_check_off, - type_check_off, case_sensitive_on, array_row_major, macro_expansion_c, @@ -847,6 +831,7 @@ const struct language_defn c_language_defn = c_print_typedef, /* Print a typedef using appropriate syntax */ c_val_print, /* Print a value using appropriate syntax */ c_value_print, /* Print a top-level value */ + default_read_var_value, /* la_read_var_value */ NULL, /* Language specific skip_trampoline */ NULL, /* name_of_this */ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ @@ -863,7 +848,7 @@ const struct language_defn c_language_defn = default_print_array_index, default_pass_by_reference, c_get_string, - strcmp_iw_ordered, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, LANG_MAGIC }; @@ -955,7 +940,6 @@ const struct language_defn cplus_language_defn = "c++", /* Language name */ language_cplus, range_check_off, - type_check_off, case_sensitive_on, array_row_major, macro_expansion_c, @@ -970,6 +954,7 @@ const struct language_defn cplus_language_defn = c_print_typedef, /* Print a typedef using appropriate syntax */ c_val_print, /* Print a value using appropriate syntax */ c_value_print, /* Print a top-level value */ + default_read_var_value, /* la_read_var_value */ cplus_skip_trampoline, /* Language specific skip_trampoline */ "this", /* name_of_this */ cp_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ @@ -986,7 +971,7 @@ const struct language_defn cplus_language_defn = default_print_array_index, cp_pass_by_reference, c_get_string, - strcmp_iw_ordered, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, LANG_MAGIC }; @@ -996,7 +981,6 @@ const struct language_defn asm_language_defn = "asm", /* Language name */ language_asm, range_check_off, - type_check_off, case_sensitive_on, array_row_major, macro_expansion_c, @@ -1011,6 +995,7 @@ const struct language_defn asm_language_defn = c_print_typedef, /* Print a typedef using appropriate syntax */ c_val_print, /* Print a value using appropriate syntax */ c_value_print, /* Print a top-level value */ + default_read_var_value, /* la_read_var_value */ NULL, /* Language specific skip_trampoline */ NULL, /* name_of_this */ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ @@ -1027,7 +1012,7 @@ const struct language_defn asm_language_defn = default_print_array_index, default_pass_by_reference, c_get_string, - strcmp_iw_ordered, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, LANG_MAGIC }; @@ -1042,7 +1027,6 @@ const struct language_defn minimal_language_defn = "minimal", /* Language name */ language_minimal, range_check_off, - type_check_off, case_sensitive_on, array_row_major, macro_expansion_c, @@ -1057,6 +1041,7 @@ const struct language_defn minimal_language_defn = c_print_typedef, /* Print a typedef using appropriate syntax */ c_val_print, /* Print a value using appropriate syntax */ c_value_print, /* Print a top-level value */ + default_read_var_value, /* la_read_var_value */ NULL, /* Language specific skip_trampoline */ NULL, /* name_of_this */ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ @@ -1073,7 +1058,7 @@ const struct language_defn minimal_language_defn = default_print_array_index, default_pass_by_reference, c_get_string, - strcmp_iw_ordered, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, LANG_MAGIC }; diff --git a/contrib/gdb-7/gdb/c-lang.h b/contrib/gdb-7/gdb/c-lang.h index e8c632f4ce..6bf6591c86 100644 --- a/contrib/gdb-7/gdb/c-lang.h +++ b/contrib/gdb-7/gdb/c-lang.h @@ -1,7 +1,6 @@ /* C language support definitions for GDB, the GNU debugger. - Copyright (C) 1992, 1994-1998, 2000, 2002, 2005-2012 Free Software - Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -24,6 +23,7 @@ struct ui_file; struct language_arch_info; +struct type_print_options; #include "value.h" #include "macroexp.h" @@ -65,20 +65,21 @@ extern int c_parse_escape (char **, struct obstack *); /* Defined in c-typeprint.c */ extern void c_print_type (struct type *, const char *, - struct ui_file *, int, int); + struct ui_file *, int, int, + const struct type_print_options *); extern void c_print_typedef (struct type *, struct symbol *, struct ui_file *); -extern int c_val_print (struct type *, const gdb_byte *, - int, CORE_ADDR, - struct ui_file *, int, - const struct value *, - const struct value_print_options *); +extern void c_val_print (struct type *, const gdb_byte *, + int, CORE_ADDR, + struct ui_file *, int, + const struct value *, + const struct value_print_options *); -extern int c_value_print (struct value *, struct ui_file *, - const struct value_print_options *); +extern void c_value_print (struct value *, struct ui_file *, + const struct value_print_options *); /* These are in c-lang.c: */ @@ -110,7 +111,7 @@ extern const struct op_print c_op_print_tab[]; /* These are in c-typeprint.c: */ extern void c_type_print_base (struct type *, struct ui_file *, - int, int); + int, int, const struct type_print_options *); /* These are in cp-valprint.c */ diff --git a/contrib/gdb-7/gdb/c-typeprint.c b/contrib/gdb-7/gdb/c-typeprint.c index db254dce29..ca8d89b0e9 100644 --- a/contrib/gdb-7/gdb/c-typeprint.c +++ b/contrib/gdb-7/gdb/c-typeprint.c @@ -1,6 +1,5 @@ /* Support for printing C and C++ types for GDB, the GNU debugger. - Copyright (C) 1986, 1988-1989, 1991-1996, 1998-2003, 2006-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -34,46 +33,93 @@ #include "jv-lang.h" #include "gdb_string.h" #include +#include "cp-support.h" static void c_type_print_varspec_prefix (struct type *, struct ui_file *, - int, int, int); + int, int, int, + const struct type_print_options *); /* Print "const", "volatile", or address space modifiers. */ static void c_type_print_modifier (struct type *, struct ui_file *, int, int); + +/* A callback function for cp_canonicalize_string_full that uses + find_typedef_in_hash. */ + +static const char * +find_typedef_for_canonicalize (struct type *t, void *data) +{ + return find_typedef_in_hash (data, t); +} + +/* Print NAME on STREAM. If the 'raw' field of FLAGS is not set, + canonicalize NAME using the local typedefs first. */ + +static void +print_name_maybe_canonical (const char *name, + const struct type_print_options *flags, + struct ui_file *stream) +{ + char *s = NULL; + + if (!flags->raw) + s = cp_canonicalize_string_full (name, + find_typedef_for_canonicalize, + (void *) flags); + + fputs_filtered (s ? s : name, stream); + xfree (s); +} + + + /* LEVEL is the depth to indent lines by. */ void c_print_type (struct type *type, const char *varstring, struct ui_file *stream, - int show, int level) + int show, int level, + const struct type_print_options *flags) { enum type_code code; int demangled_args; int need_post_space; + const char *local_name; if (show > 0) CHECK_TYPEDEF (type); - c_type_print_base (type, stream, show, level); - code = TYPE_CODE (type); - if ((varstring != NULL && *varstring != '\0') - /* Need a space if going to print stars or brackets; - but not if we will print just a type name. */ - || ((show > 0 || TYPE_NAME (type) == 0) - && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC - || code == TYPE_CODE_METHOD - || code == TYPE_CODE_ARRAY - || code == TYPE_CODE_MEMBERPTR - || code == TYPE_CODE_METHODPTR - || code == TYPE_CODE_REF))) - fputs_filtered (" ", stream); - need_post_space = (varstring != NULL && strcmp (varstring, "") != 0); - c_type_print_varspec_prefix (type, stream, show, 0, need_post_space); + local_name = find_typedef_in_hash (flags, type); + if (local_name != NULL) + { + fputs_filtered (local_name, stream); + if (varstring != NULL && *varstring != '\0') + fputs_filtered (" ", stream); + } + else + { + c_type_print_base (type, stream, show, level, flags); + code = TYPE_CODE (type); + if ((varstring != NULL && *varstring != '\0') + /* Need a space if going to print stars or brackets; + but not if we will print just a type name. */ + || ((show > 0 || TYPE_NAME (type) == 0) + && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC + || code == TYPE_CODE_METHOD + || (code == TYPE_CODE_ARRAY + && !TYPE_VECTOR (type)) + || code == TYPE_CODE_MEMBERPTR + || code == TYPE_CODE_METHODPTR + || code == TYPE_CODE_REF))) + fputs_filtered (" ", stream); + need_post_space = (varstring != NULL && strcmp (varstring, "") != 0); + c_type_print_varspec_prefix (type, stream, show, 0, need_post_space, + flags); + } if (varstring != NULL) { @@ -81,10 +127,13 @@ c_print_type (struct type *type, /* For demangled function names, we have the arglist as part of the name, so don't print an additional pair of ()'s. */ - - demangled_args = strchr (varstring, '(') != NULL; - c_type_print_varspec_suffix (type, stream, show, - 0, demangled_args); + if (local_name == NULL) + { + demangled_args = strchr (varstring, '(') != NULL; + c_type_print_varspec_suffix (type, stream, show, + 0, demangled_args, + flags); + } } } @@ -131,22 +180,19 @@ c_print_typedef (struct type *type, } In general, gdb should try to print the types as closely as - possible to the form that they appear in the source code. - - Note that in case of protected derivation gcc will not say - 'protected' but 'private'. The HP's aCC compiler emits specific - information for derivation via protected inheritance, so gdb can - print it out */ + possible to the form that they appear in the source code. */ static void cp_type_print_derivation_info (struct ui_file *stream, - struct type *type) + struct type *type, + const struct type_print_options *flags) { - char *name; + const char *name; int i; for (i = 0; i < TYPE_N_BASECLASSES (type); i++) { + wrap_here (" "); fputs_filtered (i == 0 ? ": " : ", ", stream); fprintf_filtered (stream, "%s%s ", BASETYPE_VIA_PUBLIC (type, i) @@ -154,7 +200,10 @@ cp_type_print_derivation_info (struct ui_file *stream, ? "protected" : "private"), BASETYPE_VIA_VIRTUAL (type, i) ? " virtual" : ""); name = type_name_no_tag (TYPE_BASECLASS (type, i)); - fprintf_filtered (stream, "%s", name ? name : "(null)"); + if (name) + print_name_maybe_canonical (name, flags, stream); + else + fprintf_filtered (stream, "(null)"); } if (i > 0) { @@ -165,9 +214,10 @@ cp_type_print_derivation_info (struct ui_file *stream, /* Print the C++ method arguments ARGS to the file STREAM. */ static void -cp_type_print_method_args (struct type *mtype, char *prefix, - char *varstring, int staticp, - struct ui_file *stream) +cp_type_print_method_args (struct type *mtype, const char *prefix, + const char *varstring, int staticp, + struct ui_file *stream, + const struct type_print_options *flags) { struct field *args = TYPE_FIELDS (mtype); int nargs = TYPE_NFIELDS (mtype); @@ -186,12 +236,15 @@ cp_type_print_method_args (struct type *mtype, char *prefix, { while (i < nargs) { - type_print (args[i++].type, "", stream, 0); + c_print_type (args[i++].type, "", stream, 0, 0, flags); if (i == nargs && varargs) fprintf_filtered (stream, ", ..."); else if (i < nargs) - fprintf_filtered (stream, ", "); + { + fprintf_filtered (stream, ", "); + wrap_here (" "); + } } } else if (varargs) @@ -216,6 +269,9 @@ cp_type_print_method_args (struct type *mtype, char *prefix, if (TYPE_VOLATILE (domain)) fprintf_filtered (stream, " volatile"); + + if (TYPE_RESTRICT (domain)) + fprintf_filtered (stream, " restrict"); } } @@ -236,9 +292,10 @@ static void c_type_print_varspec_prefix (struct type *type, struct ui_file *stream, int show, int passed_a_ptr, - int need_post_space) + int need_post_space, + const struct type_print_options *flags) { - char *name; + const char *name; if (type == 0) return; @@ -252,39 +309,39 @@ c_type_print_varspec_prefix (struct type *type, { case TYPE_CODE_PTR: c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, show, 1, 1); + stream, show, 1, 1, flags); fprintf_filtered (stream, "*"); c_type_print_modifier (type, stream, 1, need_post_space); break; case TYPE_CODE_MEMBERPTR: c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, show, 0, 0); + stream, show, 0, 0, flags); name = type_name_no_tag (TYPE_DOMAIN_TYPE (type)); if (name) - fputs_filtered (name, stream); + print_name_maybe_canonical (name, flags, stream); else c_type_print_base (TYPE_DOMAIN_TYPE (type), - stream, 0, passed_a_ptr); + stream, -1, passed_a_ptr, flags); fprintf_filtered (stream, "::*"); break; case TYPE_CODE_METHODPTR: c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, show, 0, 0); + stream, show, 0, 0, flags); fprintf_filtered (stream, "("); name = type_name_no_tag (TYPE_DOMAIN_TYPE (type)); if (name) - fputs_filtered (name, stream); + print_name_maybe_canonical (name, flags, stream); else c_type_print_base (TYPE_DOMAIN_TYPE (type), - stream, 0, passed_a_ptr); + stream, -1, passed_a_ptr, flags); fprintf_filtered (stream, "::*"); break; case TYPE_CODE_REF: c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, show, 1, 0); + stream, show, 1, 0, flags); fprintf_filtered (stream, "&"); c_type_print_modifier (type, stream, 1, need_post_space); break; @@ -292,21 +349,21 @@ c_type_print_varspec_prefix (struct type *type, case TYPE_CODE_METHOD: case TYPE_CODE_FUNC: c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, show, 0, 0); + stream, show, 0, 0, flags); if (passed_a_ptr) fprintf_filtered (stream, "("); break; case TYPE_CODE_ARRAY: c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, show, 0, 0); + stream, show, 0, 0, flags); if (passed_a_ptr) fprintf_filtered (stream, "("); break; case TYPE_CODE_TYPEDEF: c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, show, 0, 0); + stream, show, passed_a_ptr, 0, flags); break; case TYPE_CODE_UNDEF: @@ -322,7 +379,6 @@ c_type_print_varspec_prefix (struct type *type, case TYPE_CODE_SET: case TYPE_CODE_RANGE: case TYPE_CODE_STRING: - case TYPE_CODE_BITSTRING: case TYPE_CODE_COMPLEX: case TYPE_CODE_NAMESPACE: case TYPE_CODE_DECFLOAT: @@ -369,6 +425,14 @@ c_type_print_modifier (struct type *type, struct ui_file *stream, did_print_modifier = 1; } + if (TYPE_RESTRICT (type)) + { + if (did_print_modifier || need_pre_space) + fprintf_filtered (stream, " "); + fprintf_filtered (stream, "restrict"); + did_print_modifier = 1; + } + address_space_id = address_space_int_to_name (get_type_arch (type), TYPE_INSTANCE_FLAGS (type)); if (address_space_id) @@ -395,15 +459,13 @@ c_type_print_modifier (struct type *type, struct ui_file *stream, void c_type_print_args (struct type *type, struct ui_file *stream, - int linkage_name, enum language language) + int linkage_name, enum language language, + const struct type_print_options *flags) { - int i, len; - struct field *args; + int i; int printed_any = 0; fprintf_filtered (stream, "("); - args = TYPE_FIELDS (type); - len = TYPE_NFIELDS (type); for (i = 0; i < TYPE_NFIELDS (type); i++) { @@ -433,9 +495,9 @@ c_type_print_args (struct type *type, struct ui_file *stream, } if (language == language_java) - java_print_type (param_type, "", stream, -1, 0); + java_print_type (param_type, "", stream, -1, 0, flags); else - c_print_type (param_type, "", stream, -1, 0); + c_print_type (param_type, "", stream, -1, 0, flags); printed_any = 1; } @@ -471,7 +533,7 @@ is_type_conversion_operator (struct type *type, int i, int j) by their name is pretty terrible. But I don't think our present data structure gives us any other way to tell. If you know of some other way, feel free to rewrite this function. */ - char *name = TYPE_FN_FIELDLIST_NAME (type, i); + const char *name = TYPE_FN_FIELDLIST_NAME (type, i); if (strncmp (name, "operator", 8) != 0) return 0; @@ -604,7 +666,8 @@ void c_type_print_varspec_suffix (struct type *type, struct ui_file *stream, int show, int passed_a_ptr, - int demangled_args) + int demangled_args, + const struct type_print_options *flags) { if (type == 0) return; @@ -619,36 +682,38 @@ c_type_print_varspec_suffix (struct type *type, case TYPE_CODE_ARRAY: { LONGEST low_bound, high_bound; + int is_vector = TYPE_VECTOR (type); if (passed_a_ptr) fprintf_filtered (stream, ")"); - fprintf_filtered (stream, "["); + fprintf_filtered (stream, (is_vector ? + " __attribute__ ((vector_size(" : "[")); if (get_array_bounds (type, &low_bound, &high_bound)) - fprintf_filtered (stream, "%d", - (int) (high_bound - low_bound + 1)); - fprintf_filtered (stream, "]"); + fprintf_filtered (stream, "%s", + plongest (high_bound - low_bound + 1)); + fprintf_filtered (stream, (is_vector ? ")))" : "]")); c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, - show, 0, 0); + show, 0, 0, flags); } break; case TYPE_CODE_MEMBERPTR: c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, - show, 0, 0); + show, 0, 0, flags); break; case TYPE_CODE_METHODPTR: fprintf_filtered (stream, ")"); c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, - show, 0, 0); + show, 0, 0, flags); break; case TYPE_CODE_PTR: case TYPE_CODE_REF: c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, - show, 1, 0); + show, 1, 0, flags); break; case TYPE_CODE_METHOD: @@ -656,14 +721,15 @@ c_type_print_varspec_suffix (struct type *type, if (passed_a_ptr) fprintf_filtered (stream, ")"); if (!demangled_args) - c_type_print_args (type, stream, 0, current_language->la_language); + c_type_print_args (type, stream, 0, current_language->la_language, + flags); c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, - show, passed_a_ptr, 0); + show, passed_a_ptr, 0, flags); break; case TYPE_CODE_TYPEDEF: c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, - show, passed_a_ptr, 0); + show, passed_a_ptr, 0, flags); break; case TYPE_CODE_UNDEF: @@ -679,7 +745,6 @@ c_type_print_varspec_suffix (struct type *type, case TYPE_CODE_SET: case TYPE_CODE_RANGE: case TYPE_CODE_STRING: - case TYPE_CODE_BITSTRING: case TYPE_CODE_COMPLEX: case TYPE_CODE_NAMESPACE: case TYPE_CODE_DECFLOAT: @@ -693,6 +758,56 @@ c_type_print_varspec_suffix (struct type *type, } } +/* A helper for c_type_print_base that displays template + parameters and their bindings, if needed. + + TABLE is the local bindings table to use. If NULL, no printing is + done. Note that, at this point, TABLE won't have any useful + information in it -- but it is also used as a flag to + print_name_maybe_canonical to activate searching the global typedef + table. + + TYPE is the type whose template arguments are being displayed. + + STREAM is the stream on which to print. */ + +static void +c_type_print_template_args (const struct type_print_options *flags, + struct type *type, struct ui_file *stream) +{ + int first = 1, i; + + if (flags->raw) + return; + + for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (type); ++i) + { + struct symbol *sym = TYPE_TEMPLATE_ARGUMENT (type, i); + + if (SYMBOL_CLASS (sym) != LOC_TYPEDEF) + continue; + + if (first) + { + wrap_here (" "); + fprintf_filtered (stream, _("[with %s = "), + SYMBOL_LINKAGE_NAME (sym)); + first = 0; + } + else + { + fputs_filtered (", ", stream); + wrap_here (" "); + fprintf_filtered (stream, "%s = ", SYMBOL_LINKAGE_NAME (sym)); + } + + c_print_type (SYMBOL_TYPE (sym), "", stream, -1, 0, flags); + } + + if (!first) + fputs_filtered (_("] "), stream); +} + /* Print the name of the type (or the ultimate pointer target, function value or array element), or the description of a structure or union. @@ -713,11 +828,10 @@ c_type_print_varspec_suffix (struct type *type, void c_type_print_base (struct type *type, struct ui_file *stream, - int show, int level) + int show, int level, const struct type_print_options *flags) { int i; int len, real_len; - int lastval; enum { s_none, s_public, s_private, s_protected @@ -728,7 +842,6 @@ c_type_print_base (struct type *type, struct ui_file *stream, QUIT; - wrap_here (" "); if (type == NULL) { fputs_filtered (_(""), stream); @@ -746,7 +859,7 @@ c_type_print_base (struct type *type, struct ui_file *stream, && TYPE_NAME (type) != NULL) { c_type_print_modifier (type, stream, 0, 1); - fputs_filtered (TYPE_NAME (type), stream); + print_name_maybe_canonical (TYPE_NAME (type), flags, stream); return; } @@ -770,207 +883,242 @@ c_type_print_base (struct type *type, struct ui_file *stream, case TYPE_CODE_METHOD: case TYPE_CODE_METHODPTR: c_type_print_base (TYPE_TARGET_TYPE (type), - stream, show, level); + stream, show, level, flags); break; case TYPE_CODE_STRUCT: - c_type_print_modifier (type, stream, 0, 1); - if (TYPE_DECLARED_CLASS (type)) - fprintf_filtered (stream, "class "); - else - fprintf_filtered (stream, "struct "); - goto struct_union; - case TYPE_CODE_UNION: - c_type_print_modifier (type, stream, 0, 1); - fprintf_filtered (stream, "union "); - - struct_union: - - /* Print the tag if it exists. The HP aCC compiler emits a - spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed - enum}" tag for unnamed struct/union/enum's, which we don't - want to print. */ - if (TYPE_TAG_NAME (type) != NULL - && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8)) - { - fputs_filtered (TYPE_TAG_NAME (type), stream); - if (show > 0) - fputs_filtered (" ", stream); - } - wrap_here (" "); - if (show < 0) - { - /* If we just printed a tag name, no need to print anything - else. */ - if (TYPE_TAG_NAME (type) == NULL) - fprintf_filtered (stream, "{...}"); - } - else if (show > 0 || TYPE_TAG_NAME (type) == NULL) - { - struct type *basetype; - int vptr_fieldno; - - cp_type_print_derivation_info (stream, type); - - fprintf_filtered (stream, "{\n"); - if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0 - && TYPE_TYPEDEF_FIELD_COUNT (type) == 0) - { - if (TYPE_STUB (type)) - fprintfi_filtered (level + 4, stream, - _("\n")); - else - fprintfi_filtered (level + 4, stream, - _("\n")); - } - - /* Start off with no specific section type, so we can print - one for the first field we find, and use that section type - thereafter until we find another type. */ - - section_type = s_none; - - /* For a class, if all members are private, there's no need - for a "private:" label; similarly, for a struct or union - masquerading as a class, if all members are public, there's - no need for a "public:" label. */ - - if (TYPE_DECLARED_CLASS (type)) - { - QUIT; - len = TYPE_NFIELDS (type); - for (i = TYPE_N_BASECLASSES (type); i < len; i++) - if (!TYPE_FIELD_PRIVATE (type, i)) - { - need_access_label = 1; - break; - } - QUIT; - if (!need_access_label) - { - len2 = TYPE_NFN_FIELDS (type); - for (j = 0; j < len2; j++) + { + struct type_print_options local_flags = *flags; + struct type_print_options semi_local_flags = *flags; + struct cleanup *local_cleanups = make_cleanup (null_cleanup, NULL); + + local_flags.local_typedefs = NULL; + semi_local_flags.local_typedefs = NULL; + + if (!flags->raw) + { + if (flags->local_typedefs) + local_flags.local_typedefs + = copy_typedef_hash (flags->local_typedefs); + else + local_flags.local_typedefs = create_typedef_hash (); + + make_cleanup_free_typedef_hash (local_flags.local_typedefs); + } + + c_type_print_modifier (type, stream, 0, 1); + if (TYPE_CODE (type) == TYPE_CODE_UNION) + fprintf_filtered (stream, "union "); + else if (TYPE_DECLARED_CLASS (type)) + fprintf_filtered (stream, "class "); + else + fprintf_filtered (stream, "struct "); + + /* Print the tag if it exists. The HP aCC compiler emits a + spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed + enum}" tag for unnamed struct/union/enum's, which we don't + want to print. */ + if (TYPE_TAG_NAME (type) != NULL + && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8)) + { + /* When printing the tag name, we are still effectively + printing in the outer context, hence the use of FLAGS + here. */ + print_name_maybe_canonical (TYPE_TAG_NAME (type), flags, stream); + if (show > 0) + fputs_filtered (" ", stream); + } + + if (show < 0) + { + /* If we just printed a tag name, no need to print anything + else. */ + if (TYPE_TAG_NAME (type) == NULL) + fprintf_filtered (stream, "{...}"); + } + else if (show > 0 || TYPE_TAG_NAME (type) == NULL) + { + struct type *basetype; + int vptr_fieldno; + + c_type_print_template_args (&local_flags, type, stream); + + /* Add in template parameters when printing derivation info. */ + add_template_parameters (local_flags.local_typedefs, type); + cp_type_print_derivation_info (stream, type, &local_flags); + + /* This holds just the global typedefs and the template + parameters. */ + semi_local_flags.local_typedefs + = copy_typedef_hash (local_flags.local_typedefs); + if (semi_local_flags.local_typedefs) + make_cleanup_free_typedef_hash (semi_local_flags.local_typedefs); + + /* Now add in the local typedefs. */ + recursively_update_typedef_hash (local_flags.local_typedefs, type); + + fprintf_filtered (stream, "{\n"); + if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0 + && TYPE_TYPEDEF_FIELD_COUNT (type) == 0) + { + if (TYPE_STUB (type)) + fprintfi_filtered (level + 4, stream, + _("\n")); + else + fprintfi_filtered (level + 4, stream, + _("\n")); + } + + /* Start off with no specific section type, so we can print + one for the first field we find, and use that section type + thereafter until we find another type. */ + + section_type = s_none; + + /* For a class, if all members are private, there's no need + for a "private:" label; similarly, for a struct or union + masquerading as a class, if all members are public, there's + no need for a "public:" label. */ + + if (TYPE_DECLARED_CLASS (type)) + { + QUIT; + len = TYPE_NFIELDS (type); + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + if (!TYPE_FIELD_PRIVATE (type, i)) { - len = TYPE_FN_FIELDLIST_LENGTH (type, j); - for (i = 0; i < len; i++) - if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type, - j), i)) - { - need_access_label = 1; - break; - } - if (need_access_label) - break; + need_access_label = 1; + break; } - } - } - else - { - QUIT; - len = TYPE_NFIELDS (type); - for (i = TYPE_N_BASECLASSES (type); i < len; i++) - if (TYPE_FIELD_PRIVATE (type, i) - || TYPE_FIELD_PROTECTED (type, i)) + QUIT; + if (!need_access_label) { - need_access_label = 1; - break; + len2 = TYPE_NFN_FIELDS (type); + for (j = 0; j < len2; j++) + { + len = TYPE_FN_FIELDLIST_LENGTH (type, j); + for (i = 0; i < len; i++) + if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type, + j), i)) + { + need_access_label = 1; + break; + } + if (need_access_label) + break; + } } - QUIT; - if (!need_access_label) - { - len2 = TYPE_NFN_FIELDS (type); - for (j = 0; j < len2; j++) + } + else + { + QUIT; + len = TYPE_NFIELDS (type); + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + if (TYPE_FIELD_PRIVATE (type, i) + || TYPE_FIELD_PROTECTED (type, i)) { - QUIT; - len = TYPE_FN_FIELDLIST_LENGTH (type, j); - for (i = 0; i < len; i++) - if (TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type, - j), i) - || TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type, - j), - i)) - { - need_access_label = 1; - break; - } - if (need_access_label) - break; + need_access_label = 1; + break; } - } - } + QUIT; + if (!need_access_label) + { + len2 = TYPE_NFN_FIELDS (type); + for (j = 0; j < len2; j++) + { + QUIT; + len = TYPE_FN_FIELDLIST_LENGTH (type, j); + for (i = 0; i < len; i++) + if (TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type, + j), i) + || TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type, + j), + i)) + { + need_access_label = 1; + break; + } + if (need_access_label) + break; + } + } + } - /* If there is a base class for this type, - do not print the field that it occupies. */ + /* If there is a base class for this type, + do not print the field that it occupies. */ - len = TYPE_NFIELDS (type); - vptr_fieldno = get_vptr_fieldno (type, &basetype); - for (i = TYPE_N_BASECLASSES (type); i < len; i++) - { - QUIT; + len = TYPE_NFIELDS (type); + vptr_fieldno = get_vptr_fieldno (type, &basetype); + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + { + QUIT; - /* If we have a virtual table pointer, omit it. Even if - virtual table pointers are not specifically marked in - the debug info, they should be artificial. */ - if ((i == vptr_fieldno && type == basetype) - || TYPE_FIELD_ARTIFICIAL (type, i)) - continue; + /* If we have a virtual table pointer, omit it. Even if + virtual table pointers are not specifically marked in + the debug info, they should be artificial. */ + if ((i == vptr_fieldno && type == basetype) + || TYPE_FIELD_ARTIFICIAL (type, i)) + continue; - if (need_access_label) - { - if (TYPE_FIELD_PROTECTED (type, i)) - { - if (section_type != s_protected) - { - section_type = s_protected; - fprintfi_filtered (level + 2, stream, - "protected:\n"); - } - } - else if (TYPE_FIELD_PRIVATE (type, i)) - { - if (section_type != s_private) - { - section_type = s_private; - fprintfi_filtered (level + 2, stream, - "private:\n"); - } - } - else - { - if (section_type != s_public) - { - section_type = s_public; - fprintfi_filtered (level + 2, stream, - "public:\n"); - } - } - } + if (need_access_label) + { + if (TYPE_FIELD_PROTECTED (type, i)) + { + if (section_type != s_protected) + { + section_type = s_protected; + fprintfi_filtered (level + 2, stream, + "protected:\n"); + } + } + else if (TYPE_FIELD_PRIVATE (type, i)) + { + if (section_type != s_private) + { + section_type = s_private; + fprintfi_filtered (level + 2, stream, + "private:\n"); + } + } + else + { + if (section_type != s_public) + { + section_type = s_public; + fprintfi_filtered (level + 2, stream, + "public:\n"); + } + } + } - print_spaces_filtered (level + 4, stream); - if (field_is_static (&TYPE_FIELD (type, i))) - fprintf_filtered (stream, "static "); - c_print_type (TYPE_FIELD_TYPE (type, i), - TYPE_FIELD_NAME (type, i), - stream, show - 1, level + 4); - if (!field_is_static (&TYPE_FIELD (type, i)) - && TYPE_FIELD_PACKED (type, i)) - { - /* It is a bitfield. This code does not attempt - to look at the bitpos and reconstruct filler, - unnamed fields. This would lead to misleading - results if the compiler does not put out fields - for such things (I don't know what it does). */ - fprintf_filtered (stream, " : %d", - TYPE_FIELD_BITSIZE (type, i)); - } - fprintf_filtered (stream, ";\n"); - } + print_spaces_filtered (level + 4, stream); + if (field_is_static (&TYPE_FIELD (type, i))) + fprintf_filtered (stream, "static "); + c_print_type (TYPE_FIELD_TYPE (type, i), + TYPE_FIELD_NAME (type, i), + stream, show - 1, level + 4, + &local_flags); + if (!field_is_static (&TYPE_FIELD (type, i)) + && TYPE_FIELD_PACKED (type, i)) + { + /* It is a bitfield. This code does not attempt + to look at the bitpos and reconstruct filler, + unnamed fields. This would lead to misleading + results if the compiler does not put out fields + for such things (I don't know what it does). */ + fprintf_filtered (stream, " : %d", + TYPE_FIELD_BITSIZE (type, i)); + } + fprintf_filtered (stream, ";\n"); + } /* If there are both fields and methods, put a blank line between them. Make sure to count only method that we will display; artificial methods will be hidden. */ len = TYPE_NFN_FIELDS (type); + if (!flags->print_methods) + len = 0; real_len = 0; for (i = 0; i < len; i++) { @@ -990,8 +1138,8 @@ c_type_print_base (struct type *type, struct ui_file *stream, { struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i); - char *method_name = TYPE_FN_FIELDLIST_NAME (type, i); - char *name = type_name_no_tag (type); + const char *method_name = TYPE_FN_FIELDLIST_NAME (type, i); + const char *name = type_name_no_tag (type); int is_constructor = name && strcmp (method_name, name) == 0; @@ -1002,7 +1150,8 @@ c_type_print_base (struct type *type, struct ui_file *stream, struct cleanup *inner_cleanup; const char *physname = TYPE_FN_FIELD_PHYSNAME (f, j); int is_full_physname_constructor = - is_constructor_name (physname) + TYPE_FN_FIELD_CONSTRUCTOR (f, j) + || is_constructor_name (physname) || is_destructor_name (physname) || method_name[0] == '~'; @@ -1060,8 +1209,9 @@ c_type_print_base (struct type *type, struct ui_file *stream, && !is_full_physname_constructor /* " " */ && !is_type_conversion_operator (type, i, j)) { - type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), - "", stream, -1); + c_print_type (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), + "", stream, -1, 0, + &local_flags); fputs_filtered (" ", stream); } if (TYPE_FN_FIELD_STUB (f, j)) @@ -1082,10 +1232,10 @@ c_type_print_base (struct type *type, struct ui_file *stream, if (demangled_name == NULL) { /* In some cases (for instance with the HP - demangling), if a function has more than 10 - arguments, the demangling will fail. - Let's try to reconstruct the function - signature from the symbol information. */ + demangling), if a function has more than 10 + arguments, the demangling will fail. + Let's try to reconstruct the function + signature from the symbol information. */ if (!TYPE_FN_FIELD_STUB (f, j)) { int staticp = TYPE_FN_FIELD_STATIC_P (f, j); @@ -1095,7 +1245,7 @@ c_type_print_base (struct type *type, struct ui_file *stream, "", method_name, staticp, - stream); + stream, &local_flags); } else fprintf_filtered (stream, @@ -1137,35 +1287,38 @@ c_type_print_base (struct type *type, struct ui_file *stream, /* Print typedefs defined in this class. */ - if (TYPE_TYPEDEF_FIELD_COUNT (type) != 0) + if (TYPE_TYPEDEF_FIELD_COUNT (type) != 0 && flags->print_typedefs) { if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0) fprintf_filtered (stream, "\n"); - for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++) - { - struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i); - - /* Dereference the typedef declaration itself. */ - gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF); - target = TYPE_TARGET_TYPE (target); - - print_spaces_filtered (level + 4, stream); - fprintf_filtered (stream, "typedef "); - c_print_type (target, TYPE_TYPEDEF_FIELD_NAME (type, i), - stream, show - 1, level + 4); - fprintf_filtered (stream, ";\n"); - } - } + for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++) + { + struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i); + + /* Dereference the typedef declaration itself. */ + gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF); + target = TYPE_TARGET_TYPE (target); + + print_spaces_filtered (level + 4, stream); + fprintf_filtered (stream, "typedef "); + + /* We want to print typedefs with substitutions + from the template parameters or globally-known + typedefs but not local typedefs. */ + c_print_type (target, + TYPE_TYPEDEF_FIELD_NAME (type, i), + stream, show - 1, level + 4, + &semi_local_flags); + fprintf_filtered (stream, ";\n"); + } + } - fprintfi_filtered (level, stream, "}"); + fprintfi_filtered (level, stream, "}"); + } - if (TYPE_LOCALTYPE_PTR (type) && show >= 0) - fprintfi_filtered (level, - stream, _(" (Local at %s:%d)\n"), - TYPE_LOCALTYPE_FILE (type), - TYPE_LOCALTYPE_LINE (type)); - } + do_cleanups (local_cleanups); + } break; case TYPE_CODE_ENUM: @@ -1179,7 +1332,7 @@ c_type_print_base (struct type *type, struct ui_file *stream, if (TYPE_TAG_NAME (type) != NULL && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8)) { - fputs_filtered (TYPE_TAG_NAME (type), stream); + print_name_maybe_canonical (TYPE_TAG_NAME (type), flags, stream); if (show > 0) fputs_filtered (" ", stream); } @@ -1194,9 +1347,10 @@ c_type_print_base (struct type *type, struct ui_file *stream, } else if (show > 0 || TYPE_TAG_NAME (type) == NULL) { + LONGEST lastval = 0; + fprintf_filtered (stream, "{"); len = TYPE_NFIELDS (type); - lastval = 0; for (i = 0; i < len; i++) { QUIT; @@ -1204,11 +1358,11 @@ c_type_print_base (struct type *type, struct ui_file *stream, fprintf_filtered (stream, ", "); wrap_here (" "); fputs_filtered (TYPE_FIELD_NAME (type, i), stream); - if (lastval != TYPE_FIELD_BITPOS (type, i)) + if (lastval != TYPE_FIELD_ENUMVAL (type, i)) { - fprintf_filtered (stream, " = %d", - TYPE_FIELD_BITPOS (type, i)); - lastval = TYPE_FIELD_BITPOS (type, i); + fprintf_filtered (stream, " = %s", + plongest (TYPE_FIELD_ENUMVAL (type, i))); + lastval = TYPE_FIELD_ENUMVAL (type, i); } lastval++; } @@ -1246,7 +1400,7 @@ c_type_print_base (struct type *type, struct ui_file *stream, if (TYPE_NAME (type) != NULL) { c_type_print_modifier (type, stream, 0, 1); - fputs_filtered (TYPE_NAME (type), stream); + print_name_maybe_canonical (TYPE_NAME (type), flags, stream); } else { diff --git a/contrib/gdb-7/gdb/c-valprint.c b/contrib/gdb-7/gdb/c-valprint.c index 9949015d86..cf7f5b750a 100644 --- a/contrib/gdb-7/gdb/c-valprint.c +++ b/contrib/gdb-7/gdb/c-valprint.c @@ -1,7 +1,6 @@ /* Support for printing C values for GDB, the GNU debugger. - Copyright (C) 1986, 1988-1989, 1991-2001, 2003, 2005-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -31,31 +30,6 @@ #include "target.h" -/* Print function pointer with inferior address ADDRESS onto stdio - stream STREAM. */ - -static void -print_function_pointer_address (struct gdbarch *gdbarch, - CORE_ADDR address, - struct ui_file *stream, - int addressprint) -{ - CORE_ADDR func_addr - = gdbarch_convert_from_func_ptr_addr (gdbarch, address, - ¤t_target); - - /* If the function pointer is represented by a description, print - the address of the description. */ - if (addressprint && func_addr != address) - { - fputs_filtered ("@", stream); - fputs_filtered (paddress (gdbarch, address), stream); - fputs_filtered (": ", stream); - } - print_address_demangle (gdbarch, func_addr, stream, demangle); -} - - /* A helper for c_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. */ @@ -141,11 +115,22 @@ c_textual_element_type (struct type *type, char format) return 0; } +/* Decorations for C. */ + +static const struct generic_val_print_decorations c_decorations = +{ + "", + " + ", + " * I", + "true", + "false", + "void" +}; + /* See val_print for a description of the various parameters of this - function; they are identical. The semantics of the return value is - also identical to val_print. */ + function; they are identical. */ -int +void c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR address, struct ui_file *stream, int recurse, @@ -159,7 +144,6 @@ c_val_print (struct type *type, const gdb_byte *valaddr, struct type *elttype, *unresolved_elttype; struct type *unresolved_type = type; unsigned eltlen; - LONGEST val; CORE_ADDR addr; CHECK_TYPEDEF (type); @@ -192,6 +176,8 @@ c_val_print (struct type *type, const gdb_byte *valaddr, TARGET_CHAR_BIT * embedded_offset, TARGET_CHAR_BIT * TYPE_LENGTH (type))) { + int force_ellipses = 0; + /* If requested, look for the first null char and only print elements up to it. */ if (options->stop_print_at_null) @@ -206,12 +192,26 @@ c_val_print (struct type *type, const gdb_byte *valaddr, eltlen, byte_order) != 0); ++temp_len) ; + + /* Force LA_PRINT_STRING to print ellipses if + we've printed the maximum characters and + the next character is not \000. */ + if (temp_len == options->print_max && temp_len < len) + { + ULONGEST val + = extract_unsigned_integer (valaddr + embedded_offset + + temp_len * eltlen, + eltlen, byte_order); + if (val != 0) + force_ellipses = 1; + } + len = temp_len; } LA_PRINT_STRING (stream, unresolved_elttype, valaddr + embedded_offset, len, - NULL, 0, options); + NULL, force_ellipses, options); i = len; } else @@ -242,16 +242,6 @@ c_val_print (struct type *type, const gdb_byte *valaddr, addr = address + embedded_offset; goto print_unpacked_pointer; - case TYPE_CODE_MEMBERPTR: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - break; - } - cp_print_class_member (valaddr + embedded_offset, type, stream, "&"); - break; - case TYPE_CODE_METHODPTR: cplus_print_method_ptr (valaddr + embedded_offset, type, stream); break; @@ -272,28 +262,34 @@ c_val_print (struct type *type, const gdb_byte *valaddr, CORE_ADDR addr = extract_typed_address (valaddr + embedded_offset, type); - print_function_pointer_address (gdbarch, addr, stream, - options->addressprint); + print_function_pointer_address (options, gdbarch, addr, stream); break; } unresolved_elttype = TYPE_TARGET_TYPE (type); elttype = check_typedef (unresolved_elttype); { + int want_space; + addr = unpack_pointer (type, valaddr + embedded_offset); print_unpacked_pointer: + want_space = 0; + if (TYPE_CODE (elttype) == TYPE_CODE_FUNC) { /* Try to print what function it points to. */ - print_function_pointer_address (gdbarch, addr, stream, - options->addressprint); - /* Return value is irrelevant except for string - pointers. */ - return (0); + print_function_pointer_address (options, gdbarch, addr, stream); + return; } - if (options->addressprint) - fputs_filtered (paddress (gdbarch, addr), stream); + if (options->symbol_print) + want_space = print_address_demangle (options, gdbarch, addr, + stream, demangle); + else if (options->addressprint) + { + fputs_filtered (paddress (gdbarch, addr), stream); + want_space = 1; + } /* For a pointer to a textual type, also print the string pointed to, unless pointer is null. */ @@ -302,6 +298,8 @@ c_val_print (struct type *type, const gdb_byte *valaddr, options->format) && addr != 0) { + if (want_space) + fputs_filtered (" ", stream); i = val_print_string (unresolved_elttype, NULL, addr, -1, stream, options); @@ -312,23 +310,32 @@ c_val_print (struct type *type, const gdb_byte *valaddr, CORE_ADDR vt_address = unpack_pointer (type, valaddr + embedded_offset); - struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (vt_address); - if ((msymbol != NULL) + + /* If 'symbol_print' is set, we did the work above. */ + if (!options->symbol_print + && (msymbol != NULL) && (vt_address == SYMBOL_VALUE_ADDRESS (msymbol))) { + if (want_space) + fputs_filtered (" ", stream); fputs_filtered (" <", stream); fputs_filtered (SYMBOL_PRINT_NAME (msymbol), stream); fputs_filtered (">", stream); + want_space = 1; } + if (vt_address && options->vtblprint) { struct value *vt_val; struct symbol *wsym = (struct symbol *) NULL; struct type *wtype; struct block *block = (struct block *) NULL; - int is_this_fld; + struct field_of_this_result is_this_fld; + + if (want_space) + fputs_filtered (" ", stream); if (msymbol != NULL) wsym = lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol), @@ -353,51 +360,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, } } } - - /* Return number of characters printed, including the - terminating '\0' if we reached the end. val_print_string - takes care including the terminating '\0' if - necessary. */ - return i; - } - break; - - case TYPE_CODE_REF: - elttype = check_typedef (TYPE_TARGET_TYPE (type)); - if (options->addressprint) - { - CORE_ADDR addr - = extract_typed_address (valaddr + embedded_offset, type); - - fprintf_filtered (stream, "@"); - fputs_filtered (paddress (gdbarch, addr), stream); - if (options->deref_ref) - fputs_filtered (": ", stream); - } - /* De-reference the reference. */ - if (options->deref_ref) - { - if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF) - { - struct value *deref_val; - - deref_val = coerce_ref_if_computed (original_value); - if (deref_val != NULL) - { - /* More complicated computed references are not supported. */ - gdb_assert (embedded_offset == 0); - } - else - deref_val = value_at (TYPE_TARGET_TYPE (type), - unpack_pointer (type, - (valaddr - + embedded_offset))); - - common_val_print (deref_val, stream, recurse, options, - current_language); - } - else - fputs_filtered ("???", stream); + return; } break; @@ -424,8 +387,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, CORE_ADDR addr = extract_typed_address (valaddr + offset, field_type); - print_function_pointer_address (gdbarch, addr, stream, - options->addressprint); + print_function_pointer_address (options, gdbarch, addr, stream); } else cp_print_value_fields_rtti (type, valaddr, @@ -435,91 +397,6 @@ c_val_print (struct type *type, const gdb_byte *valaddr, NULL, 0); break; - case TYPE_CODE_ENUM: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - break; - } - len = TYPE_NFIELDS (type); - val = unpack_long (type, valaddr + embedded_offset); - for (i = 0; i < len; i++) - { - QUIT; - if (val == TYPE_FIELD_BITPOS (type, i)) - { - break; - } - } - if (i < len) - { - fputs_filtered (TYPE_FIELD_NAME (type, i), stream); - } - else - { - print_longest (stream, 'd', 0, val); - } - break; - - case TYPE_CODE_FLAGS: - if (options->format) - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - else - val_print_type_code_flags (type, valaddr + embedded_offset, - stream); - break; - - case TYPE_CODE_FUNC: - case TYPE_CODE_METHOD: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - break; - } - /* FIXME, we should consider, at least for ANSI C language, - eliminating the distinction made between FUNCs and POINTERs - to FUNCs. */ - fprintf_filtered (stream, "{"); - type_print (type, "", stream, -1); - fprintf_filtered (stream, "} "); - /* Try to print what function it points to, and its address. */ - print_address_demangle (gdbarch, address, stream, demangle); - break; - - case TYPE_CODE_BOOL: - if (options->format || options->output_format) - { - struct value_print_options opts = *options; - opts.format = (options->format ? options->format - : options->output_format); - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, &opts, 0, stream); - } - else - { - val = unpack_long (type, valaddr + embedded_offset); - if (val == 0) - fputs_filtered ("false", stream); - else if (val == 1) - fputs_filtered ("true", stream); - else - print_longest (stream, 'd', 0, val); - } - break; - - case TYPE_CODE_RANGE: - /* FIXME: create_range_type does not set the unsigned bit in a - range type (I think it probably should copy it from the - target type), so we won't print values which are too large to - fit in a signed integer correctly. */ - /* FIXME: Doesn't handle ranges of enums correctly. (Can't just - print with the target type, though, because the size of our - type and the target type might differ). */ - /* FALLTHROUGH */ - case TYPE_CODE_INT: if (options->format || options->output_format) { @@ -547,98 +424,38 @@ c_val_print (struct type *type, const gdb_byte *valaddr, } break; - case TYPE_CODE_CHAR: - if (options->format || options->output_format) - { - struct value_print_options opts = *options; - opts.format = (options->format ? options->format - : options->output_format); - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, &opts, 0, stream); - } - else + case TYPE_CODE_MEMBERPTR: + if (!options->format) { - val = unpack_long (type, valaddr + embedded_offset); - if (TYPE_UNSIGNED (type)) - fprintf_filtered (stream, "%u", (unsigned int) val); - else - fprintf_filtered (stream, "%d", (int) val); - fputs_filtered (" ", stream); - LA_PRINT_CHAR (val, unresolved_type, stream); + cp_print_class_member (valaddr + embedded_offset, type, stream, "&"); + break; } - break; + /* FALLTHROUGH */ + case TYPE_CODE_REF: + case TYPE_CODE_ENUM: + case TYPE_CODE_FLAGS: + case TYPE_CODE_FUNC: + case TYPE_CODE_METHOD: + case TYPE_CODE_BOOL: + case TYPE_CODE_RANGE: case TYPE_CODE_FLT: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - } - else - { - print_floating (valaddr + embedded_offset, type, stream); - } - break; - case TYPE_CODE_DECFLOAT: - if (options->format) - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - else - print_decimal_floating (valaddr + embedded_offset, - type, stream); - break; - case TYPE_CODE_VOID: - fprintf_filtered (stream, "void"); - break; - case TYPE_CODE_ERROR: - fprintf_filtered (stream, "%s", TYPE_ERROR_NAME (type)); - break; - case TYPE_CODE_UNDEF: - /* This happens (without TYPE_FLAG_STUB set) on systems which - don't use dbx xrefs (NO_DBX_XREFS in gcc) if a file has a - "struct foo *bar" and no complete type for struct foo in that - file. */ - fprintf_filtered (stream, _("")); - break; - case TYPE_CODE_COMPLEX: - if (options->format) - val_print_scalar_formatted (TYPE_TARGET_TYPE (type), - valaddr, embedded_offset, - original_value, options, 0, stream); - else - print_floating (valaddr + embedded_offset, - TYPE_TARGET_TYPE (type), - stream); - fprintf_filtered (stream, " + "); - if (options->format) - val_print_scalar_formatted (TYPE_TARGET_TYPE (type), - valaddr, - embedded_offset - + TYPE_LENGTH (TYPE_TARGET_TYPE (type)), - original_value, - options, 0, stream); - else - print_floating (valaddr + embedded_offset - + TYPE_LENGTH (TYPE_TARGET_TYPE (type)), - TYPE_TARGET_TYPE (type), - stream); - fprintf_filtered (stream, " * I"); - break; - + case TYPE_CODE_CHAR: default: - error (_("Invalid C/C++ type code %d in symbol table."), - TYPE_CODE (type)); + generic_val_print (type, valaddr, embedded_offset, address, + stream, recurse, original_value, options, + &c_decorations); + break; } gdb_flush (stream); - return (0); } -int +void c_value_print (struct value *val, struct ui_file *stream, const struct value_print_options *options) { @@ -697,22 +514,13 @@ c_value_print (struct value *val, struct ui_file *stream, if (value_entirely_available (val)) { - real_type = value_rtti_target_type (val, &full, &top, &using_enc); + real_type = value_rtti_indirect_type (val, &full, &top, + &using_enc); if (real_type) { /* RTTI entry found. */ - if (TYPE_CODE (type) == TYPE_CODE_PTR) - { - /* Create a pointer type pointing to the real - type. */ - type = lookup_pointer_type (real_type); - } - else - { - /* Create a reference type referencing the real - type. */ - type = lookup_reference_type (real_type); - } + type = real_type; + /* Need to adjust pointer value. */ val = value_from_pointer (type, value_as_address (val) - top); @@ -751,10 +559,11 @@ c_value_print (struct value *val, struct ui_file *stream, full ? "" : _(" [incomplete object]")); /* Print out object: enclosing type is same as real_type if full. */ - return val_print (value_enclosing_type (val), - value_contents_for_printing (val), 0, - value_address (val), stream, 0, - val, &opts, current_language); + val_print (value_enclosing_type (val), + value_contents_for_printing (val), 0, + value_address (val), stream, 0, + val, &opts, current_language); + return; /* Note: When we look up RTTI entries, we don't get any information on const or volatile attributes. */ } @@ -763,17 +572,18 @@ c_value_print (struct value *val, struct ui_file *stream, /* No RTTI information, so let's do our best. */ fprintf_filtered (stream, "(%s ?) ", TYPE_NAME (value_enclosing_type (val))); - return val_print (value_enclosing_type (val), - value_contents_for_printing (val), 0, - value_address (val), stream, 0, - val, &opts, current_language); + val_print (value_enclosing_type (val), + value_contents_for_printing (val), 0, + value_address (val), stream, 0, + val, &opts, current_language); + return; } /* Otherwise, we end up at the return outside this "if". */ } - return val_print (val_type, value_contents_for_printing (val), - value_embedded_offset (val), - value_address (val), - stream, 0, - val, &opts, current_language); + val_print (val_type, value_contents_for_printing (val), + value_embedded_offset (val), + value_address (val), + stream, 0, + val, &opts, current_language); } diff --git a/contrib/gdb-7/gdb/call-cmds.h b/contrib/gdb-7/gdb/call-cmds.h deleted file mode 100644 index e98585b950..0000000000 --- a/contrib/gdb-7/gdb/call-cmds.h +++ /dev/null @@ -1,34 +0,0 @@ -/* ***DEPRECATED*** The gdblib files must not be calling/using things in any - of the possible command languages. If necessary, a hook (that may be - present or not) must be used and set to the appropriate routine by any - command language that cares about it. If you are having to include this - file you are possibly doing things the old way. This file will disapear. - 2000-12-01 fnasser@redhat.com */ - -/* Prototypes for GDB commands that are called internally by other functions. - Copyright (C) 1992, 2000-2001, 2007-2012 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 . */ - -#ifndef CALL_CMDS_H -#define CALL_CMDS_H - -extern void initialize_all_files (void); - -extern void core_file_command (char *, int); - -extern void break_command (char *, int); - -#endif diff --git a/contrib/gdb-7/gdb/cc-with-index.sh b/contrib/gdb-7/gdb/cc-with-index.sh deleted file mode 100644 index 22eefaacbf..0000000000 --- a/contrib/gdb-7/gdb/cc-with-index.sh +++ /dev/null @@ -1,126 +0,0 @@ -#! /bin/sh -# Wrapper around gcc to add the .gdb_index section when running the testsuite. - -# Copyright (C) 2010-2012 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 requires gdb and objcopy in addition to gcc. -# The default values are gdb from the build tree and objcopy from $PATH. -# They may be overridden by setting environment variables GDB and OBJCOPY -# respectively. -# We assume the current directory is either $obj/gdb or $obj/gdb/testsuite. -# -# Example usage: -# -# bash$ cd $objdir/gdb/testsuite -# bash$ runtest \ -# CC_FOR_TARGET="/bin/sh $srcdir/cc-with-index.sh gcc" \ -# CXX_FOR_TARGET="/bin/sh $srcdir/cc-with-index.sh g++" -# -# For documentation on index files: info -f gdb.info -n "Index Files" - -myname=cc-with-index.sh - -if [ -z "$GDB" ] -then - if [ -f ./gdb ] - then - GDB="./gdb" - elif [ -f ../gdb ] - then - GDB="../gdb" - elif [ -f ../../gdb ] - then - GDB="../../gdb" - else - echo "$myname: unable to find usable gdb" >&2 - exit 1 - fi -fi - -OBJCOPY=${OBJCOPY:-objcopy} - -have_link=unknown -next_is_output_file=no -output_file=a.out - -for arg in "$@" -do - if [ "$next_is_output_file" = "yes" ] - then - output_file="$arg" - next_is_output_file=no - continue - fi - - # Poor man's gcc argument parser. - # We don't need to handle all arguments, we just need to know if we're - # doing a link and what the output file is. - # It's not perfect, but it seems to work well enough for the task at hand. - case "$arg" in - "-c") have_link=no ;; - "-E") have_link=no ;; - "-S") have_link=no ;; - "-o") next_is_output_file=yes ;; - esac -done - -if [ "$next_is_output_file" = "yes" ] -then - echo "$myname: Unable to find output file" >&2 - exit 1 -fi - -if [ "$have_link" = "no" ] -then - "$@" - exit $? -fi - -index_file="${output_file}.gdb-index" -if [ -f "$index_file" ] -then - echo "$myname: Index file $index_file exists, won't clobber." >&2 - exit 1 -fi - -output_dir="${output_file%/*}" -[ "$output_dir" = "$output_file" ] && output_dir="." - -"$@" -rc=$? -[ $rc != 0 ] && exit $rc -if [ ! -f "$output_file" ] -then - echo "$myname: Internal error: $output_file missing." >&2 - exit 1 -fi - -$GDB --batch-silent -nx -ex "file $output_file" -ex "save gdb-index $output_dir" -rc=$? -[ $rc != 0 ] && exit $rc - -# GDB might not always create an index. Cope. -if [ -f "$index_file" ] -then - $OBJCOPY --add-section .gdb_index="$index_file" \ - --set-section-flags .gdb_index=readonly \ - "$output_file" "$output_file" - rc=$? -else - rc=0 -fi - -rm -f "$index_file" -exit $rc diff --git a/contrib/gdb-7/gdb/charset-list.h b/contrib/gdb-7/gdb/charset-list.h index d0eff82906..69cf7f42c7 100644 --- a/contrib/gdb-7/gdb/charset-list.h +++ b/contrib/gdb-7/gdb/charset-list.h @@ -1,6 +1,6 @@ /* List of character set names for GDB. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/charset.c b/contrib/gdb-7/gdb/charset.c index f32736a5f7..5835fd4087 100644 --- a/contrib/gdb-7/gdb/charset.c +++ b/contrib/gdb-7/gdb/charset.c @@ -1,6 +1,6 @@ /* Character set conversion support for GDB. - Copyright (C) 2001, 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -27,6 +27,7 @@ #include "vec.h" #include "environ.h" #include "arch-utils.h" +#include "gdb_vecs.h" #include #include "gdb_string.h" @@ -107,7 +108,7 @@ #define EILSEQ ENOENT #endif -iconv_t +static iconv_t phony_iconv_open (const char *to, const char *from) { /* We allow conversions from UTF-32BE, wchar_t, and the host charset. @@ -123,13 +124,13 @@ phony_iconv_open (const char *to, const char *from) return !strcmp (from, "UTF-32BE"); } -int +static int phony_iconv_close (iconv_t arg) { return 0; } -size_t +static size_t phony_iconv (iconv_t utf_flag, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { @@ -473,7 +474,7 @@ convert_between_encodings (const char *from, const char *to, iconv_t desc; struct cleanup *cleanups; size_t inleft; - char *inp; + ICONV_CONST char *inp; unsigned int space_request; /* Often, the host and target charsets will be the same. */ @@ -489,7 +490,7 @@ convert_between_encodings (const char *from, const char *to, cleanups = make_cleanup (cleanup_iconv, &desc); inleft = num_bytes; - inp = (char *) bytes; + inp = (ICONV_CONST char *) bytes; space_request = num_bytes; @@ -505,7 +506,7 @@ convert_between_encodings (const char *from, const char *to, outp = obstack_base (output) + old_size; outleft = space_request; - r = iconv (desc, (ICONV_CONST char **) &inp, &inleft, &outp, &outleft); + r = iconv (desc, &inp, &inleft, &outp, &outleft); /* Now make sure that the object on the obstack only includes bytes we have converted. */ @@ -530,7 +531,7 @@ convert_between_encodings (const char *from, const char *to, { char octal[5]; - sprintf (octal, "\\%.3o", *inp & 0xff); + xsnprintf (octal, sizeof (octal), "\\%.3o", *inp & 0xff); obstack_grow_str (output, octal); ++inp; @@ -570,7 +571,7 @@ struct wchar_iterator iconv_t desc; /* The input string. This is updated as convert characters. */ - char *input; + const gdb_byte *input; /* The number of bytes remaining in the input. */ size_t bytes; @@ -596,7 +597,7 @@ make_wchar_iterator (const gdb_byte *input, size_t bytes, result = XNEW (struct wchar_iterator); result->desc = desc; - result->input = (char *) input; + result->input = input; result->bytes = bytes; result->width = width; @@ -639,14 +640,15 @@ wchar_iterate (struct wchar_iterator *iter, out_request = 1; while (iter->bytes > 0) { + ICONV_CONST char *inptr = (ICONV_CONST char *) iter->input; char *outptr = (char *) &iter->out[0]; - char *orig_inptr = iter->input; + const gdb_byte *orig_inptr = iter->input; size_t orig_in = iter->bytes; size_t out_avail = out_request * sizeof (gdb_wchar_t); size_t num; - size_t r = iconv (iter->desc, - (ICONV_CONST char **) &iter->input, - &iter->bytes, &outptr, &out_avail); + size_t r = iconv (iter->desc, &inptr, &iter->bytes, &outptr, &out_avail); + + iter->input = (gdb_byte *) inptr; if (r == (size_t) -1) { @@ -717,8 +719,6 @@ wchar_iterate (struct wchar_iterator *iter, extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */ -DEF_VEC_P (char_ptr); - static VEC (char_ptr) *charsets; #ifdef PHONY_ICONV @@ -840,7 +840,7 @@ find_charset_names (void) parse the glibc and libiconv formats; feel free to add others as needed. */ - while (!feof (in)) + while (in != NULL && !feof (in)) { /* The size of buf is chosen arbitrarily. */ char buf[1024]; @@ -910,11 +910,8 @@ find_charset_names (void) if (fail) { /* Some error occurred, so drop the vector. */ - int ix; - char *elt; - for (ix = 0; VEC_iterate (char_ptr, charsets, ix, elt); ++ix) - xfree (elt); - VEC_truncate (char_ptr, charsets, 0); + free_char_ptr_vec (charsets); + charsets = NULL; } else VEC_safe_push (char_ptr, charsets, NULL); @@ -969,7 +966,6 @@ intermediate_encoding (void) iconv_t desc; static const char *stored_result = NULL; char *result; - int i; if (stored_result) return stored_result; diff --git a/contrib/gdb-7/gdb/charset.h b/contrib/gdb-7/gdb/charset.h index 0bfdd807ce..9ec3296392 100644 --- a/contrib/gdb-7/gdb/charset.h +++ b/contrib/gdb-7/gdb/charset.h @@ -1,5 +1,5 @@ /* Character set conversion support for GDB. - Copyright (C) 2001, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/cleanups.c b/contrib/gdb-7/gdb/cleanups.c new file mode 100644 index 0000000000..c403db7cc2 --- /dev/null +++ b/contrib/gdb-7/gdb/cleanups.c @@ -0,0 +1,293 @@ +/* Cleanup routines for GDB, the GNU debugger. + + Copyright (C) 1986-2013 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 "gdb_assert.h" + +/* The cleanup list records things that have to be undone + if an error happens (descriptors to be closed, memory to be freed, etc.) + Each link in the chain records a function to call and an + argument to give it. + + Use make_cleanup to add an element to the cleanup chain. + Use do_cleanups to do all cleanup actions back to a given + point in the chain. Use discard_cleanups to remove cleanups + from the chain back to a given point, not doing them. + + If the argument is pointer to allocated memory, then you need + to additionally set the 'free_arg' member to a function that will + free that memory. This function will be called both when the cleanup + is executed and when it's discarded. */ + +struct cleanup +{ + struct cleanup *next; + void (*function) (void *); + void (*free_arg) (void *); + void *arg; +}; + +/* Used to mark the end of a cleanup chain. + The value is chosen so that it: + - is non-NULL so that make_cleanup never returns NULL, + - causes a segv if dereferenced + [though this won't catch errors that a value of, say, + ((struct cleanup *) -1) will] + - displays as something useful when printed in gdb. + This is const for a bit of extra robustness. + It is initialized to coax gcc into putting it into .rodata. + All fields are initialized to survive -Wextra. */ +static const struct cleanup sentinel_cleanup = { 0, 0, 0, 0 }; + +/* Handy macro to use when referring to sentinel_cleanup. */ +#define SENTINEL_CLEANUP ((struct cleanup *) &sentinel_cleanup) + +/* Chain of cleanup actions established with make_cleanup, + to be executed if an error happens. */ +static struct cleanup *cleanup_chain = SENTINEL_CLEANUP; + +/* Chain of cleanup actions established with make_final_cleanup, + to be executed when gdb exits. */ +static struct cleanup *final_cleanup_chain = SENTINEL_CLEANUP; + +/* Main worker routine to create a cleanup. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + FUNCTION is the function to call to perform the cleanup. + ARG is passed to FUNCTION when called. + FREE_ARG, if non-NULL, is called after the cleanup is performed. + + The result is a pointer to the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. */ + +static struct cleanup * +make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function, + void *arg, void (*free_arg) (void *)) +{ + struct cleanup *new + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + struct cleanup *old_chain = *pmy_chain; + + new->next = *pmy_chain; + new->function = function; + new->free_arg = free_arg; + new->arg = arg; + *pmy_chain = new; + + gdb_assert (old_chain != NULL); + return old_chain; +} + +/* Worker routine to create a cleanup without a destructor. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + FUNCTION is the function to call to perform the cleanup. + ARG is passed to FUNCTION when called. + + The result is a pointer to the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. */ + +static struct cleanup * +make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function, + void *arg) +{ + return make_my_cleanup2 (pmy_chain, function, arg, NULL); +} + +/* Add a new cleanup to the cleanup_chain, + and return the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. + Args are FUNCTION to clean up with, and ARG to pass to it. */ + +struct cleanup * +make_cleanup (make_cleanup_ftype *function, void *arg) +{ + return make_my_cleanup (&cleanup_chain, function, arg); +} + +/* Same as make_cleanup except also includes TDOR, a destructor to free ARG. + DTOR is invoked when the cleanup is performed or when it is discarded. */ + +struct cleanup * +make_cleanup_dtor (make_cleanup_ftype *function, void *arg, + void (*dtor) (void *)) +{ + return make_my_cleanup2 (&cleanup_chain, + function, arg, dtor); +} + +/* Same as make_cleanup except the cleanup is added to final_cleanup_chain. */ + +struct cleanup * +make_final_cleanup (make_cleanup_ftype *function, void *arg) +{ + return make_my_cleanup (&final_cleanup_chain, function, arg); +} + +/* Worker routine to perform cleanups. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + OLD_CHAIN is the result of a "make" cleanup routine. + Cleanups are performed until we get back to the old end of the chain. */ + +static void +do_my_cleanups (struct cleanup **pmy_chain, + struct cleanup *old_chain) +{ + struct cleanup *ptr; + + while ((ptr = *pmy_chain) != old_chain) + { + *pmy_chain = ptr->next; /* Do this first in case of recursion. */ + (*ptr->function) (ptr->arg); + if (ptr->free_arg) + (*ptr->free_arg) (ptr->arg); + xfree (ptr); + } +} + +/* Return a value that can be passed to do_cleanups, do_final_cleanups to + indicate perform all cleanups. */ + +struct cleanup * +all_cleanups (void) +{ + return SENTINEL_CLEANUP; +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +do_cleanups (struct cleanup *old_chain) +{ + do_my_cleanups (&cleanup_chain, old_chain); +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the final_cleanup_chain. */ + +void +do_final_cleanups (struct cleanup *old_chain) +{ + do_my_cleanups (&final_cleanup_chain, old_chain); +} + +/* Main worker routine to discard cleanups. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + OLD_CHAIN is the result of a "make" cleanup routine. + Cleanups are discarded until we get back to the old end of the chain. */ + +static void +discard_my_cleanups (struct cleanup **pmy_chain, + struct cleanup *old_chain) +{ + struct cleanup *ptr; + + while ((ptr = *pmy_chain) != old_chain) + { + *pmy_chain = ptr->next; + if (ptr->free_arg) + (*ptr->free_arg) (ptr->arg); + xfree (ptr); + } +} + +/* Discard cleanups, not doing the actions they describe, + until we get back to the point OLD_CHAIN in the cleanup chain. */ + +void +discard_cleanups (struct cleanup *old_chain) +{ + discard_my_cleanups (&cleanup_chain, old_chain); +} + +/* Discard final cleanups, not doing the actions they describe, + until we get back to the point OLD_CHAIN in the final cleanup chain. */ + +void +discard_final_cleanups (struct cleanup *old_chain) +{ + discard_my_cleanups (&final_cleanup_chain, old_chain); +} + +/* Main worker routine to save cleanups. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + The chain is emptied and the result is a pointer to the old chain. */ + +static struct cleanup * +save_my_cleanups (struct cleanup **pmy_chain) +{ + struct cleanup *old_chain = *pmy_chain; + + *pmy_chain = SENTINEL_CLEANUP; + return old_chain; +} + +/* Set the cleanup_chain to 0, and return the old cleanup_chain. */ + +struct cleanup * +save_cleanups (void) +{ + return save_my_cleanups (&cleanup_chain); +} + +/* Set the final_cleanup_chain to 0, and return the old + final_cleanup_chain. */ + +struct cleanup * +save_final_cleanups (void) +{ + return save_my_cleanups (&final_cleanup_chain); +} + +/* Main worker routine to save cleanups. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + The chain is restored from CHAIN. */ + +static void +restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain) +{ + *pmy_chain = chain; +} + +/* Restore the cleanup chain from a previously saved chain. */ + +void +restore_cleanups (struct cleanup *chain) +{ + restore_my_cleanups (&cleanup_chain, chain); +} + +/* Restore the final cleanup chain from a previously saved chain. */ + +void +restore_final_cleanups (struct cleanup *chain) +{ + restore_my_cleanups (&final_cleanup_chain, chain); +} + +/* Provide a known function that does nothing, to use as a base for + a possibly long chain of cleanups. This is useful where we + use the cleanup chain for handling normal cleanups as well as dealing + with cleanups that need to be done as a result of a call to error(). + In such cases, we may not be certain where the first cleanup is, unless + we have a do-nothing one to always use as the base. */ + +void +null_cleanup (void *arg) +{ +} diff --git a/contrib/gdb-7/gdb/cleanups.h b/contrib/gdb-7/gdb/cleanups.h new file mode 100644 index 0000000000..463b923ff4 --- /dev/null +++ b/contrib/gdb-7/gdb/cleanups.h @@ -0,0 +1,69 @@ +/* Cleanups. + Copyright (C) 1986-2013 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 CLEANUPS_H +#define CLEANUPS_H + +/* Outside of cleanups.c, this is an opaque type. */ +struct cleanup; + +/* NOTE: cagney/2000-03-04: This typedef is strictly for the + make_cleanup function declarations below. Do not use this typedef + as a cast when passing functions into the make_cleanup() code. + Instead either use a bounce function or add a wrapper function. + Calling a f(char*) function with f(void*) is non-portable. */ +typedef void (make_cleanup_ftype) (void *); + +/* Function type for the dtor in make_cleanup_dtor. */ +typedef void (make_cleanup_dtor_ftype) (void *); + +/* WARNING: The result of the "make cleanup" routines is not the intuitive + choice of being a handle on the just-created cleanup. Instead it is an + opaque handle of the cleanup mechanism and represents all cleanups created + from that point onwards. + The result is guaranteed to be non-NULL though. */ + +extern struct cleanup *make_cleanup (make_cleanup_ftype *, void *); + +extern struct cleanup *make_cleanup_dtor (make_cleanup_ftype *, void *, + make_cleanup_dtor_ftype *); + +extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *); + +/* A special value to pass to do_cleanups and do_final_cleanups + to tell them to do all cleanups. */ +extern struct cleanup *all_cleanups (void); + +extern void do_cleanups (struct cleanup *); +extern void do_final_cleanups (struct cleanup *); + +extern void discard_cleanups (struct cleanup *); +extern void discard_final_cleanups (struct cleanup *); + +extern struct cleanup *save_cleanups (void); +extern struct cleanup *save_final_cleanups (void); + +extern void restore_cleanups (struct cleanup *); +extern void restore_final_cleanups (struct cleanup *); + +/* A no-op cleanup. + This is useful when you want to establish a known reference point + to pass to do_cleanups. */ +extern void null_cleanup (void *); + +#endif /* CLEANUPS_H */ diff --git a/contrib/gdb-7/gdb/cli-out.c b/contrib/gdb-7/gdb/cli-out.c index 925206c535..380352bd37 100644 --- a/contrib/gdb-7/gdb/cli-out.c +++ b/contrib/gdb-7/gdb/cli-out.c @@ -1,7 +1,6 @@ /* Output generating routines for GDB CLI. - Copyright (C) 1999-2000, 2002-2003, 2005, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions. Written by Fernando Nasser for Cygnus. @@ -139,7 +138,7 @@ cli_field_int (struct ui_out *uiout, int fldno, int width, if (data->suppress_output) return; - sprintf (buffer, "%d", value); + xsnprintf (buffer, sizeof (buffer), "%d", value); /* Always go through the function pointer (virtual function call). We may have been extended. */ @@ -371,6 +370,7 @@ struct ui_out_impl cli_ui_out_impl = cli_wrap_hint, cli_flush, cli_redirect, + 0, 0, /* Does not need MI hacks (i.e. needs CLI hacks). */ }; diff --git a/contrib/gdb-7/gdb/cli-out.h b/contrib/gdb-7/gdb/cli-out.h index b066b7e721..c861712193 100644 --- a/contrib/gdb-7/gdb/cli-out.h +++ b/contrib/gdb-7/gdb/cli-out.h @@ -1,5 +1,5 @@ /* Output generating routines for GDB CLI. - Copyright (C) 1999-2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/cli/cli-cmds.c b/contrib/gdb-7/gdb/cli/cli-cmds.c index c38167a175..77da7382d0 100644 --- a/contrib/gdb-7/gdb/cli/cli-cmds.c +++ b/contrib/gdb-7/gdb/cli/cli-cmds.c @@ -1,6 +1,6 @@ /* GDB CLI commands. - Copyright (C) 2000-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -47,6 +47,7 @@ #include "cli/cli-script.h" #include "cli/cli-setshow.h" #include "cli/cli-cmds.h" +#include "cli/cli-utils.h" #include "python/python.h" @@ -86,8 +87,6 @@ static void edit_command (char *, int); static void list_command (char *, int); -void apropos_command (char *, int); - /* Prototypes for local utility functions */ static void ambiguous_line_spec (struct symtabs_and_lines *); @@ -96,7 +95,7 @@ static void filter_sals (struct symtabs_and_lines *); /* Limit the call depth of user-defined commands */ -int max_user_call_depth; +unsigned int max_user_call_depth; /* Define all cmd_list_elements. */ @@ -136,10 +135,6 @@ struct cmd_list_element *detachlist; struct cmd_list_element *killlist; -/* Chain containing all defined "enable breakpoint" subcommands. */ - -struct cmd_list_element *enablebreaklist; - /* Chain containing all defined set subcommands */ struct cmd_list_element *setlist; @@ -188,8 +183,6 @@ struct cmd_list_element *setchecklist; struct cmd_list_element *showchecklist; -struct cmd_list_element *skiplist; - /* Command tracing state. */ int source_verbose = 0; @@ -201,7 +194,7 @@ static const char script_ext_off[] = "off"; static const char script_ext_soft[] = "soft"; static const char script_ext_strict[] = "strict"; -static const char *script_ext_enums[] = { +static const char *const script_ext_enums[] = { script_ext_off, script_ext_soft, script_ext_strict, @@ -254,7 +247,8 @@ static void complete_command (char *arg, int from_tty) { int argpoint; - char **completions, *point, *arg_prefix; + char *point, *arg_prefix; + VEC (char_ptr) *completions; dont_repeat (); @@ -282,33 +276,28 @@ complete_command (char *arg, int from_tty) if (completions) { - int item, size; + int ix, size = VEC_length (char_ptr, completions); + char *item, *prev = NULL; - for (size = 0; completions[size]; ++size) - ; - qsort (completions, size, sizeof (char *), compare_strings); + qsort (VEC_address (char_ptr, completions), size, + sizeof (char *), compare_strings); /* We do extra processing here since we only want to print each unique item once. */ - item = 0; - while (item < size) + for (ix = 0; VEC_iterate (char_ptr, completions, ix, item); ++ix) { - int next_item; - - printf_unfiltered ("%s%s\n", arg_prefix, completions[item]); - next_item = item + 1; - while (next_item < size - && ! strcmp (completions[item], completions[next_item])) + if (prev == NULL || strcmp (item, prev) != 0) { - xfree (completions[next_item]); - ++next_item; + printf_unfiltered ("%s%s\n", arg_prefix, item); + xfree (prev); + prev = item; } - - xfree (completions[item]); - item = next_item; + else + xfree (item); } - xfree (completions); + xfree (prev); + VEC_free (char_ptr, completions); } } @@ -321,10 +310,8 @@ is_complete_command (struct cmd_list_element *c) static void show_version (char *args, int from_tty) { - immediate_quit++; print_gdb_version (gdb_stdout); printf_filtered ("\n"); - immediate_quit--; } /* Handle the quit command. */ @@ -369,7 +356,7 @@ cd_command (char *dir, int from_tty) dont_repeat (); if (dir == 0) - error_no_arg (_("new working directory")); + dir = "~"; dir = tilde_expand (dir); make_cleanup (xfree, dir); @@ -417,7 +404,7 @@ cd_command (char *dir, int from_tty) { if (IS_DIR_SEPARATOR (p[0]) && p[1] == '.' && (p[2] == 0 || IS_DIR_SEPARATOR (p[2]))) - strcpy (p, p + 2); + memmove (p, p + 2, strlen (p + 2) + 1); else if (IS_DIR_SEPARATOR (p[0]) && p[1] == '.' && p[2] == '.' && (p[3] == 0 || IS_DIR_SEPARATOR (p[3]))) { @@ -436,7 +423,7 @@ cd_command (char *dir, int from_tty) ++p; else { - strcpy (q - 1, p + 3); + memmove (q - 1, p + 3, strlen (p + 3) + 1); p = q - 1; } } @@ -477,10 +464,7 @@ show_script_ext_mode (struct ui_file *file, int from_tty, we tried to open. If SEARCH_PATH is non-zero, and the file isn't found in cwd, - search for it in the source search path. - - NOTE: This calls openp which uses xfullpath to compute the full path - instead of gdb_realpath. Symbolic links are not resolved. */ + search for it in the source search path. */ int find_and_open_script (const char *script_file, int search_path, @@ -513,11 +497,21 @@ find_and_open_script (const char *script_file, int search_path, do_cleanups (old_cleanups); *streamp = fdopen (fd, FOPEN_RT); + if (*streamp == NULL) + { + int save_errno = errno; + + close (fd); + if (full_pathp) + xfree (*full_pathp); + errno = save_errno; + return 0; + } + return 1; } -/* Load script FILE, which has already been opened as STREAM. - STREAM is closed before we return. */ +/* Load script FILE, which has already been opened as STREAM. */ static void source_script_from_stream (FILE *stream, const char *file) @@ -529,9 +523,7 @@ source_script_from_stream (FILE *stream, const char *file) TRY_CATCH (e, RETURN_MASK_ERROR) { - /* The python support reopens the file using python functions, - so there's no point in passing STREAM here. */ - source_python_script (file); + source_python_script (stream, file); } if (e.reason < 0) { @@ -545,12 +537,9 @@ source_script_from_stream (FILE *stream, const char *file) else { /* Nope, just punt. */ - fclose (stream); throw_exception (e); } } - else - fclose (stream); } else script_from_file (stream, file); @@ -584,6 +573,7 @@ source_script_with_search (const char *file, int from_tty, int search_path) } old_cleanups = make_cleanup (xfree, full_path); + make_cleanup_fclose (stream); /* The python support reopens the file, so we need to pass full_path here in case the file was found on the search path. It's useful to do this anyway so that error messages show the actual file used. But only do @@ -635,8 +625,7 @@ source_command (char *args, int from_tty) { /* Make sure leading white space does not break the comparisons. */ - while (isspace(args[0])) - args++; + args = skip_spaces (args); if (args[0] != '-') break; @@ -659,9 +648,7 @@ source_command (char *args, int from_tty) break; } - while (isspace (args[0])) - args++; - file = args; + file = skip_spaces (args); } source_script_with_search (file, from_tty, search_path); @@ -766,7 +753,8 @@ edit_command (char *arg, int from_tty) struct symbol *sym; char *arg1; char *editor; - char *p, *fn; + char *p; + const char *fn; /* Pull in the current default source line if necessary. */ if (arg == 0) @@ -828,11 +816,13 @@ edit_command (char *arg, int from_tty) printf_filtered ("%s is in %s (%s:%d).\n", paddress (gdbarch, sal.pc), SYMBOL_PRINT_NAME (sym), - sal.symtab->filename, sal.line); + symtab_to_filename_for_display (sal.symtab), + sal.line); else printf_filtered ("%s is at %s:%d.\n", paddress (gdbarch, sal.pc), - sal.symtab->filename, sal.line); + symtab_to_filename_for_display (sal.symtab), + sal.line); } /* If what was given does not imply a symtab, it must be an @@ -845,16 +835,7 @@ edit_command (char *arg, int from_tty) if ((editor = (char *) getenv ("EDITOR")) == NULL) editor = "/bin/ex"; - /* If we don't already know the full absolute file name of the - source file, find it now. */ - if (!sal.symtab->fullname) - { - fn = symtab_to_fullname (sal.symtab); - if (!fn) - fn = "unknown"; - } - else - fn = sal.symtab->fullname; + fn = symtab_to_fullname (sal.symtab); /* Quote the file name, in case it has whitespace or other special characters. */ @@ -957,7 +938,7 @@ list_command (char *arg, int from_tty) else sals_end = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, sal.symtab, sal.line); - filter_sals (&sals); + filter_sals (&sals_end); if (sals_end.nelts == 0) return; if (sals_end.nelts > 1) @@ -1000,11 +981,11 @@ list_command (char *arg, int from_tty) printf_filtered ("%s is in %s (%s:%d).\n", paddress (gdbarch, sal.pc), SYMBOL_PRINT_NAME (sym), - sal.symtab->filename, sal.line); + symtab_to_filename_for_display (sal.symtab), sal.line); else printf_filtered ("%s is at %s:%d.\n", paddress (gdbarch, sal.pc), - sal.symtab->filename, sal.line); + symtab_to_filename_for_display (sal.symtab), sal.line); } /* If line was not specified by just a line number, and it does not @@ -1091,11 +1072,11 @@ disassemble_current_function (int flags) struct frame_info *frame; struct gdbarch *gdbarch; CORE_ADDR low, high, pc; - char *name; + const char *name; frame = get_selected_frame (_("No frame selected.")); gdbarch = get_frame_arch (frame); - pc = get_frame_pc (frame); + pc = get_frame_address_in_block (frame); if (find_pc_partial_function (pc, &name, &low, &high) == 0) error (_("No function contains program counter for selected frame.")); #if defined(TUI) @@ -1129,23 +1110,25 @@ disassemble_command (char *arg, int from_tty) { struct gdbarch *gdbarch = get_current_arch (); CORE_ADDR low, high; - char *name; + const char *name; CORE_ADDR pc; int flags; + const char *p; + p = arg; name = NULL; flags = 0; - if (arg && *arg == '/') + if (p && *p == '/') { - ++arg; + ++p; - if (*arg == '\0') + if (*p == '\0') error (_("Missing modifier.")); - while (*arg && ! isspace (*arg)) + while (*p && ! isspace (*p)) { - switch (*arg++) + switch (*p++) { case 'm': flags |= DISASSEMBLY_SOURCE; @@ -1158,21 +1141,20 @@ disassemble_command (char *arg, int from_tty) } } - while (isspace (*arg)) - ++arg; + p = skip_spaces_const (p); } - if (! arg || ! *arg) + if (! p || ! *p) { flags |= DISASSEMBLY_OMIT_FNAME; disassemble_current_function (flags); return; } - pc = value_as_address (parse_to_comma_and_eval (&arg)); - if (arg[0] == ',') - ++arg; - if (arg[0] == '\0') + pc = value_as_address (parse_to_comma_and_eval (&p)); + if (p[0] == ',') + ++p; + if (p[0] == '\0') { /* One argument. */ if (find_pc_partial_function (pc, &name, &low, &high) == 0) @@ -1192,14 +1174,13 @@ disassemble_command (char *arg, int from_tty) /* Two arguments. */ int incl_flag = 0; low = pc; - while (isspace (*arg)) - arg++; - if (arg[0] == '+') + p = skip_spaces_const (p); + if (p[0] == '+') { - ++arg; + ++p; incl_flag = 1; } - high = parse_and_eval_address (arg); + high = parse_and_eval_address (p); if (incl_flag) high += low; } @@ -1235,7 +1216,8 @@ show_user (char *args, int from_tty) char *comname = args; c = lookup_cmd (&comname, cmdlist, "", 0, 1); - if (c->class != class_user) + /* c->user_commands would be NULL if it's a python command. */ + if (c->class != class_user || !c->user_commands) error (_("Not a user command.")); show_user_1 (c, "", args, gdb_stdout); } @@ -1252,7 +1234,7 @@ show_user (char *args, int from_tty) /* Search through names of commands and documentations for a certain regular expression. */ -void +static void apropos_command (char *searchstr, int from_tty) { regex_t pattern; @@ -1336,7 +1318,6 @@ alias_command (char *args, int from_tty) char *args2, *equals, *alias, *command; char **alias_argv, **command_argv; dyn_string_t alias_dyn_string, command_dyn_string; - struct cmd_list_element *c; static const char usage[] = N_("Usage: alias [-a] [--] ALIAS = COMMAND"); if (args == NULL || strchr (args, '=') == NULL) @@ -1418,7 +1399,6 @@ alias_command (char *args, int from_tty) } else { - int i; dyn_string_t alias_prefix_dyn_string, command_prefix_dyn_string; char *alias_prefix, *command_prefix; struct cmd_list_element *c_alias, *c_command; @@ -1465,7 +1445,8 @@ ambiguous_line_spec (struct symtabs_and_lines *sals) for (i = 0; i < sals->nelts; ++i) printf_filtered (_("file: \"%s\", line number: %d\n"), - sals->sals[i].symtab->filename, sals->sals[i].line); + symtab_to_filename_for_display (sals->sals[i].symtab), + sals->sals[i].line); } /* Sort function for filter_sals. */ @@ -1538,13 +1519,14 @@ filter_sals (struct symtabs_and_lines *sals) ++out; } } - sals->nelts = out; if (sals->nelts == 0) { xfree (sals->sals); sals->sals = NULL; } + else + sals->nelts = out; } static void @@ -1574,7 +1556,6 @@ init_cmd_lists (void) stoplist = NULL; deletelist = NULL; detachlist = NULL; - enablebreaklist = NULL; setlist = NULL; unsetlist = NULL; showlist = NULL; @@ -1588,7 +1569,6 @@ init_cmd_lists (void) showprintlist = NULL; setchecklist = NULL; showchecklist = NULL; - skiplist = NULL; } static void @@ -1647,11 +1627,13 @@ show_max_user_call_depth (struct ui_file *file, int from_tty, } + +initialize_file_ftype _initialize_cli_cmds; + void -init_cli_cmds (void) +_initialize_cli_cmds (void) { struct cmd_list_element *c; - char *source_help_text; /* Define the classes of commands. They will appear in the help list in alphabetical order. */ @@ -1707,30 +1689,6 @@ use \"\\n\" if you want a newline to be printed.\n\ Since leading and trailing whitespace are ignored in command arguments,\n\ if you want to print some you must use \"\\\" before leading whitespace\n\ to be printed or after trailing whitespace.")); - add_com ("document", class_support, document_command, _("\ -Document a user-defined command.\n\ -Give command name as argument. Give documentation on following lines.\n\ -End with a line of just \"end\".")); - add_com ("define", class_support, define_command, _("\ -Define a new command name. Command name is argument.\n\ -Definition appears on following lines, one command per line.\n\ -End with a line of just \"end\".\n\ -Use the \"document\" command to give documentation for the new command.\n\ -Commands defined in this way may have up to ten arguments.")); - - source_help_text = xstrprintf (_("\ -Read commands from a file named FILE.\n\ -\n\ -Usage: source [-s] [-v] FILE\n\ --s: search for the script in the source search path,\n\ - even if FILE contains directories.\n\ --v: each command in FILE is echoed as it is executed.\n\ -\n\ -Note that the file \"%s\" is read automatically in this way\n\ -when GDB is started."), gdbinit); - c = add_cmd ("source", class_support, source_command, - source_help_text, &cmdlist); - set_cmd_completer (c, filename_completer); add_setshow_enum_cmd ("script-extension", class_support, script_ext_enums, &script_ext_mode, _("\ @@ -1798,19 +1756,6 @@ the previous command number shown."), add_cmd ("version", no_set_class, show_version, _("Show what version of GDB this is."), &showlist); - add_com ("while", class_support, while_command, _("\ -Execute nested commands WHILE the conditional expression is non zero.\n\ -The conditional expression must follow the word `while' and must in turn be\n\ -followed by a new line. The nested commands must be entered one per line,\n\ -and should be terminated by the word `end'.")); - - add_com ("if", class_support, if_command, _("\ -Execute nested commands once IF the conditional expression is non zero.\n\ -The conditional expression must follow the word `if' and must in turn be\n\ -followed by a new line. The nested commands must be entered one per line,\n\ -and should be terminated by the word 'else' or `end'. If an else clause\n\ -is used, the same rules apply to its nested commands as to the first ones.")); - /* If target is open when baud changes, it doesn't take effect until the next open (I think, not sure). */ add_setshow_zinteger_cmd ("remotebaud", no_class, &baud_rate, _("\ @@ -1831,14 +1776,15 @@ is displayed."), show_remote_debug, &setdebuglist, &showdebuglist); - add_setshow_integer_cmd ("remotetimeout", no_class, &remote_timeout, _("\ + add_setshow_zuinteger_unlimited_cmd ("remotetimeout", no_class, + &remote_timeout, _("\ Set timeout limit to wait for target to respond."), _("\ Show timeout limit to wait for target to respond."), _("\ This value is used to set the time limit for gdb to wait for a response\n\ from the target."), - NULL, - show_remote_timeout, - &setlist, &showlist); + NULL, + show_remote_timeout, + &setlist, &showlist); add_prefix_cmd ("debug", no_class, set_debug, _("Generic command for setting gdb debugging flags"), @@ -1895,7 +1841,12 @@ With a /m modifier, source lines are included (if available).\n\ With a /r modifier, raw instructions in hex are included.\n\ With a single argument, the function surrounding that address is dumped.\n\ Two arguments (separated by a comma) are taken as a range of memory to dump,\n\ - in the form of \"start,end\", or \"start,+length\".")); + in the form of \"start,end\", or \"start,+length\".\n\ +\n\ +Note that the address is interpreted as an expression, not as a location\n\ +like in the \"break\" command.\n\ +So, for example, if you want to disassemble function bar in file foo.c\n\ +you must type \"disassemble 'foo.c'::bar\" and not \"disassemble foo.c:bar\".")); set_cmd_completer (c, location_completer); if (xdb_commands) add_com_alias ("va", "disassemble", class_xdb, 0); @@ -1906,19 +1857,19 @@ Two arguments (separated by a comma) are taken as a range of memory to dump,\n\ Run the ``make'' program using the rest of the line as arguments.")); set_cmd_completer (c, filename_completer); add_cmd ("user", no_class, show_user, _("\ -Show definitions of user defined commands.\n\ +Show definitions of non-python user defined commands.\n\ Argument is the name of the user defined command.\n\ With no argument, show definitions of all user defined commands."), &showlist); add_com ("apropos", class_support, apropos_command, _("Search for commands matching a REGEXP")); - add_setshow_integer_cmd ("max-user-call-depth", no_class, + add_setshow_uinteger_cmd ("max-user-call-depth", no_class, &max_user_call_depth, _("\ -Set the max call depth for user-defined commands."), _("\ -Show the max call depth for user-defined commands."), NULL, - NULL, - show_max_user_call_depth, - &setlist, &showlist); +Set the max call depth for non-python user-defined commands."), _("\ +Show the max call depth for non-python user-defined commands."), NULL, + NULL, + show_max_user_call_depth, + &setlist, &showlist); add_setshow_boolean_cmd ("trace-commands", no_class, &trace_commands, _("\ Set tracing of GDB CLI commands."), _("\ @@ -1942,3 +1893,24 @@ Make \"spe\" an alias of \"set print elements\":\n\ Make \"elms\" an alias of \"elements\" in the \"set print\" command:\n\ alias -a set print elms = set print elements")); } + +void +init_cli_cmds (void) +{ + struct cmd_list_element *c; + char *source_help_text; + + source_help_text = xstrprintf (_("\ +Read commands from a file named FILE.\n\ +\n\ +Usage: source [-s] [-v] FILE\n\ +-s: search for the script in the source search path,\n\ + even if FILE contains directories.\n\ +-v: each command in FILE is echoed as it is executed.\n\ +\n\ +Note that the file \"%s\" is read automatically in this way\n\ +when GDB is started."), gdbinit); + c = add_cmd ("source", class_support, source_command, + source_help_text, &cmdlist); + set_cmd_completer (c, filename_completer); +} diff --git a/contrib/gdb-7/gdb/cli/cli-cmds.h b/contrib/gdb-7/gdb/cli/cli-cmds.h index 4b4e74cc66..9f6977c0c6 100644 --- a/contrib/gdb-7/gdb/cli/cli-cmds.h +++ b/contrib/gdb-7/gdb/cli/cli-cmds.h @@ -1,5 +1,5 @@ /* Header file for GDB CLI command implementation library. - Copyright (c) 2000, 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 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 @@ -53,10 +53,6 @@ extern struct cmd_list_element *togglelist; extern struct cmd_list_element *stoplist; -/* Chain containing all defined "enable breakpoint" subcommands. */ - -extern struct cmd_list_element *enablebreaklist; - /* Chain containing all defined set subcommands */ extern struct cmd_list_element *setlist; @@ -105,8 +101,6 @@ extern struct cmd_list_element *setchecklist; extern struct cmd_list_element *showchecklist; -extern struct cmd_list_element *skiplist; - /* Exported to gdb/top.c */ void init_cmd_lists (void); diff --git a/contrib/gdb-7/gdb/cli/cli-decode.c b/contrib/gdb-7/gdb/cli/cli-decode.c index f168ff19d4..a8f7747ea6 100644 --- a/contrib/gdb-7/gdb/cli/cli-decode.c +++ b/contrib/gdb-7/gdb/cli/cli-decode.c @@ -1,7 +1,6 @@ /* Handle lists of commands, their decoding and documentation, for GDB. - Copyright (c) 1986, 1989-1991, 1998, 2000-2002, 2004, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 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 @@ -52,6 +51,53 @@ static struct cmd_list_element *find_cmd (char *command, static void help_all (struct ui_file *stream); +/* Look up a command whose 'prefixlist' is KEY. Return the command if found, + otherwise return NULL. */ + +static struct cmd_list_element * +lookup_cmd_for_prefixlist (struct cmd_list_element **key, + struct cmd_list_element *list) +{ + struct cmd_list_element *p = NULL; + + for (p = list; p != NULL; p = p->next) + { + struct cmd_list_element *q; + + if (p->prefixlist == NULL) + continue; + else if (p->prefixlist == key) + return p; + + q = lookup_cmd_for_prefixlist (key, *(p->prefixlist)); + if (q != NULL) + return q; + } + + return NULL; +} + +static void +set_cmd_prefix (struct cmd_list_element *c, struct cmd_list_element **list) +{ + struct cmd_list_element *p; + + /* Check to see if *LIST contains any element other than C. */ + for (p = *list; p != NULL; p = p->next) + if (p != c) + break; + + if (p == NULL) + { + /* *SET_LIST only contains SET. */ + p = lookup_cmd_for_prefixlist (list, setlist); + + c->prefix = p ? (p->cmd_pointer ? p->cmd_pointer : p) : p; + } + else + c->prefix = p->prefix; +} + static void print_help_for_command (struct cmd_list_element *c, char *prefix, int recurse, struct ui_file *stream); @@ -119,9 +165,7 @@ cmd_type (struct cmd_list_element *cmd) } void -set_cmd_completer (struct cmd_list_element *cmd, - char **(*completer) (struct cmd_list_element *self, - char *text, char *word)) +set_cmd_completer (struct cmd_list_element *cmd, completer_ftype *completer) { cmd->completer = completer; /* Ok. */ } @@ -195,6 +239,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int), c->prefixlist = NULL; c->prefixname = NULL; c->allow_unknown = 0; + c->prefix = NULL; c->abbrev_flag = 0; set_cmd_completer (c, make_symbol_completion_list_fn); c->destroyer = NULL; @@ -260,6 +305,13 @@ add_alias_cmd (char *name, char *oldname, enum command_class class, } c = add_cmd (name, class, NULL, old->doc, list); + + /* If OLD->DOC can be freed, we should make another copy. */ + if ((old->flags & DOC_ALLOCATED) != 0) + { + c->doc = xstrdup (old->doc); + c->flags |= DOC_ALLOCATED; + } /* NOTE: Both FUNC and all the FUNCTIONs need to be copied. */ c->func = old->func; c->function = old->function; @@ -270,6 +322,8 @@ add_alias_cmd (char *name, char *oldname, enum command_class class, c->cmd_pointer = old; c->alias_chain = old->aliases; old->aliases = c; + + set_cmd_prefix (c, list); return c; } @@ -286,10 +340,21 @@ add_prefix_cmd (char *name, enum command_class class, struct cmd_list_element **list) { struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + struct cmd_list_element *p; c->prefixlist = prefixlist; c->prefixname = prefixname; c->allow_unknown = allow_unknown; + + if (list == &cmdlist) + c->prefix = NULL; + else + set_cmd_prefix (c, list); + + /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */ + for (p = *prefixlist; p != NULL; p = p->next) + p->prefix = c; + return c; } @@ -392,10 +457,16 @@ add_setshow_cmd_full (char *name, } set = add_set_or_show_cmd (name, set_cmd, class, var_type, var, full_set_doc, set_list); + set->flags |= DOC_ALLOCATED; + if (set_func != NULL) set_cmd_sfunc (set, set_func); + + set_cmd_prefix (set, set_list); + show = add_set_or_show_cmd (name, show_cmd, class, var_type, var, full_show_doc, show_list); + show->flags |= DOC_ALLOCATED; show->show_value_func = show_func; if (set_result != NULL) @@ -412,7 +483,7 @@ add_setshow_cmd_full (char *name, void add_setshow_enum_cmd (char *name, enum command_class class, - const char *enumlist[], + const char *const *enumlist, const char **var, const char *set_doc, const char *show_doc, @@ -432,6 +503,8 @@ add_setshow_enum_cmd (char *name, c->enums = enumlist; } +const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL }; + /* Add an auto-boolean command named NAME to both the set and show command list lists. CLASS is as in add_cmd. VAR is address of the variable which will contain the value. DOC is the documentation @@ -447,7 +520,6 @@ add_setshow_auto_boolean_cmd (char *name, struct cmd_list_element **set_list, struct cmd_list_element **show_list) { - static const char *auto_boolean_enums[] = { "on", "off", "auto", NULL }; struct cmd_list_element *c; add_setshow_cmd_full (name, class, var_auto_boolean, var, @@ -525,7 +597,7 @@ add_setshow_string_cmd (char *name, enum command_class class, /* Add element named NAME to both the set and show command LISTs (the list for set/show or some sublist thereof). */ -void +struct cmd_list_element * add_setshow_string_noescape_cmd (char *name, enum command_class class, char **var, const char *set_doc, const char *show_doc, @@ -535,11 +607,14 @@ add_setshow_string_noescape_cmd (char *name, enum command_class class, struct cmd_list_element **set_list, struct cmd_list_element **show_list) { + struct cmd_list_element *set_cmd; + add_setshow_cmd_full (name, class, var_string_noescape, var, set_doc, show_doc, help_doc, set_func, show_func, set_list, show_list, - NULL, NULL); + &set_cmd, NULL); + return set_cmd; } /* Add element named NAME to both the set and show command LISTs (the @@ -569,7 +644,8 @@ add_setshow_optional_filename_cmd (char *name, enum command_class class, /* Add element named NAME to both the set and show command LISTs (the list for set/show or some sublist thereof). CLASS is as in add_cmd. VAR is address of the variable which will contain the - value. SET_DOC and SHOW_DOC are the documentation strings. */ + value. SET_DOC and SHOW_DOC are the documentation strings. This + function is only used in Python API. Please don't use it elsewhere. */ void add_setshow_integer_cmd (char *name, enum command_class class, int *var, @@ -629,6 +705,25 @@ add_setshow_zinteger_cmd (char *name, enum command_class class, NULL, NULL); } +void +add_setshow_zuinteger_unlimited_cmd (char *name, + enum command_class class, + int *var, + const char *set_doc, + const char *show_doc, + const char *help_doc, + cmd_sfunc_ftype *set_func, + show_value_ftype *show_func, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list) +{ + add_setshow_cmd_full (name, class, var_zuinteger_unlimited, var, + set_doc, show_doc, help_doc, + set_func, show_func, + set_list, show_list, + NULL, NULL); +} + /* Add element named NAME to both the set and show command LISTs (the list for set/show or some sublist thereof). CLASS is as in add_cmd. VAR is address of the variable which will contain the @@ -686,6 +781,8 @@ delete_cmd (char *name, struct cmd_list_element **list, *prehookee = iter->hookee_pre; if (iter->hookee_post) iter->hookee_post->hook_post = 0; + if (iter->doc && (iter->flags & DOC_ALLOCATED) != 0) + xfree (iter->doc); *posthook = iter->hook_post; *posthookee = iter->hookee_post; @@ -820,7 +917,6 @@ void help_cmd (char *command, struct ui_file *stream) { struct cmd_list_element *c; - extern struct cmd_list_element *cmdlist; if (!command) { @@ -952,7 +1048,6 @@ static void help_all (struct ui_file *stream) { struct cmd_list_element *c; - extern struct cmd_list_element *cmdlist; int seen_unclassified = 0; for (c = cmdlist; c; c = c->next) @@ -1005,8 +1100,11 @@ print_doc_line (struct ui_file *stream, char *str) line_buffer = (char *) xmalloc (line_size); } + /* Keep printing '.' or ',' not followed by a whitespace for embedded strings + like '.gdbinit'. */ p = str; - while (*p && *p != '\n' && *p != '.' && *p != ',') + while (*p && *p != '\n' + && ((*p != '.' && *p != ',') || (p[1] && !isspace (p[1])))) p++; if (p - str > line_size - 1) { @@ -1018,7 +1116,7 @@ print_doc_line (struct ui_file *stream, char *str) line_buffer[p - str] = '\0'; if (islower (line_buffer[0])) line_buffer[0] = toupper (line_buffer[0]); - ui_out_text (current_uiout, line_buffer); + fputs_filtered (line_buffer, stream); } /* Print one-line help for command C. @@ -1639,33 +1737,30 @@ lookup_cmd_composition (char *text, "foo" and we want to complete to "foobar". If WORD is "oo", return "oobar"; if WORD is "baz/foo", return "baz/foobar". */ -char ** -complete_on_cmdlist (struct cmd_list_element *list, char *text, char *word) +VEC (char_ptr) * +complete_on_cmdlist (struct cmd_list_element *list, char *text, char *word, + int ignore_help_classes) { struct cmd_list_element *ptr; - char **matchlist; - int sizeof_matchlist; - int matches; + VEC (char_ptr) *matchlist = NULL; int textlen = strlen (text); int pass; int saw_deprecated_match = 0; - sizeof_matchlist = 10; - matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *)); - matches = 0; - /* We do one or two passes. In the first pass, we skip deprecated commands. If we see no matching commands in the first pass, and if we did happen to see a matching deprecated command, we do another loop to collect those. */ - for (pass = 0; matches == 0 && pass < 2; ++pass) + for (pass = 0; matchlist == 0 && pass < 2; ++pass) { for (ptr = list; ptr; ptr = ptr->next) if (!strncmp (ptr->name, text, textlen) && !ptr->abbrev_flag - && (ptr->func + && (!ignore_help_classes || ptr->func || ptr->prefixlist)) { + char *match; + if (pass == 0) { if ((ptr->flags & CMD_DEPRECATED) != 0) @@ -1675,31 +1770,22 @@ complete_on_cmdlist (struct cmd_list_element *list, char *text, char *word) } } - if (matches == sizeof_matchlist) - { - sizeof_matchlist *= 2; - matchlist = (char **) xrealloc ((char *) matchlist, - (sizeof_matchlist - * sizeof (char *))); - } - - matchlist[matches] = (char *) - xmalloc (strlen (word) + strlen (ptr->name) + 1); + match = (char *) xmalloc (strlen (word) + strlen (ptr->name) + 1); if (word == text) - strcpy (matchlist[matches], ptr->name); + strcpy (match, ptr->name); else if (word > text) { /* Return some portion of ptr->name. */ - strcpy (matchlist[matches], ptr->name + (word - text)); + strcpy (match, ptr->name + (word - text)); } else { /* Return some of text plus ptr->name. */ - strncpy (matchlist[matches], word, text - word); - matchlist[matches][text - word] = '\0'; - strcat (matchlist[matches], ptr->name); + strncpy (match, word, text - word); + match[text - word] = '\0'; + strcat (match, ptr->name); } - ++matches; + VEC_safe_push (char_ptr, matchlist, match); } /* If we saw no matching deprecated commands in the first pass, just bail out. */ @@ -1707,18 +1793,6 @@ complete_on_cmdlist (struct cmd_list_element *list, char *text, char *word) break; } - if (matches == 0) - { - xfree (matchlist); - matchlist = 0; - } - else - { - matchlist = (char **) xrealloc ((char *) matchlist, ((matches + 1) - * sizeof (char *))); - matchlist[matches] = (char *) 0; - } - return matchlist; } @@ -1732,64 +1806,39 @@ complete_on_cmdlist (struct cmd_list_element *list, char *text, char *word) and we want to complete to "foobar". If WORD is "oo", return "oobar"; if WORD is "baz/foo", return "baz/foobar". */ -char ** -complete_on_enum (const char *enumlist[], +VEC (char_ptr) * +complete_on_enum (const char *const *enumlist, char *text, char *word) { - char **matchlist; - int sizeof_matchlist; - int matches; + VEC (char_ptr) *matchlist = NULL; int textlen = strlen (text); int i; const char *name; - sizeof_matchlist = 10; - matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *)); - matches = 0; - for (i = 0; (name = enumlist[i]) != NULL; i++) if (strncmp (name, text, textlen) == 0) { - if (matches == sizeof_matchlist) - { - sizeof_matchlist *= 2; - matchlist = (char **) xrealloc ((char *) matchlist, - (sizeof_matchlist - * sizeof (char *))); - } + char *match; - matchlist[matches] = (char *) - xmalloc (strlen (word) + strlen (name) + 1); + match = (char *) xmalloc (strlen (word) + strlen (name) + 1); if (word == text) - strcpy (matchlist[matches], name); + strcpy (match, name); else if (word > text) { /* Return some portion of name. */ - strcpy (matchlist[matches], name + (word - text)); + strcpy (match, name + (word - text)); } else { /* Return some of text plus name. */ - strncpy (matchlist[matches], word, text - word); - matchlist[matches][text - word] = '\0'; - strcat (matchlist[matches], name); + strncpy (match, word, text - word); + match[text - word] = '\0'; + strcat (match, name); } - ++matches; + VEC_safe_push (char_ptr, matchlist, match); } - if (matches == 0) - { - xfree (matchlist); - matchlist = 0; - } - else - { - matchlist = (char **) xrealloc ((char *) matchlist, ((matches + 1) - * sizeof (char *))); - matchlist[matches] = (char *) 0; - } - return matchlist; } diff --git a/contrib/gdb-7/gdb/cli/cli-decode.h b/contrib/gdb-7/gdb/cli/cli-decode.h index 56ef3ae70a..47e3a3b0b2 100644 --- a/contrib/gdb-7/gdb/cli/cli-decode.h +++ b/contrib/gdb-7/gdb/cli/cli-decode.h @@ -1,6 +1,6 @@ /* Header file for GDB command decoding library. - Copyright (c) 2000, 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 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 @@ -18,6 +18,10 @@ #if !defined (CLI_DECODE_H) #define CLI_DECODE_H 1 +/* This file defines the private interfaces for any code implementing + command internals. */ + +/* Include the public interfaces. */ #include "command.h" struct re_pattern_buffer; @@ -47,6 +51,7 @@ cmd_types; #define CMD_DEPRECATED 0x1 #define DEPRECATED_WARN_USER 0x2 #define MALLOCED_REPLACEMENT 0x4 +#define DOC_ALLOCATED 0x8 struct cmd_list_element { @@ -108,7 +113,9 @@ struct cmd_list_element memory for replacement is malloc'ed. When a command is undeprecated or re-deprecated at runtime we don't want to risk calling free on statically allocated memory, so we check this - flag. */ + flag. + + bit 3: DOC_ALLOCATED, set if the doc field should be xfree'd. */ int flags; @@ -145,6 +152,9 @@ struct cmd_list_element recognized; call the prefix's own function in that case. */ char allow_unknown; + /* The prefix command of this command. */ + struct cmd_list_element *prefix; + /* Nonzero says this is an abbreviation, and should not be mentioned in lists of commands. This allows "br" to complete to "break", which it @@ -164,8 +174,7 @@ struct cmd_list_element For example, suppose TEXT is "foo" and we want to complete to "foobar". If WORD is "oo", return "oobar"; if WORD is "baz/foo", return "baz/foobar". */ - char **(*completer) (struct cmd_list_element *cmd, - char *text, char *word); + completer_ftype *completer; /* Destruction routine for this command. If non-NULL, this is called when this command instance is destroyed. This may be @@ -185,7 +194,7 @@ struct cmd_list_element /* Pointer to NULL terminated list of enumerated values (like argv). */ - const char **enums; + const char *const *enums; /* Pointer to command strings of user-defined commands */ struct command_line *user_commands; @@ -209,94 +218,6 @@ struct cmd_list_element struct cmd_list_element *alias_chain; }; -/* Flag for an ambiguous cmd_list result. */ -#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1) - -/* API to the manipulation of command lists. */ - -extern struct cmd_list_element *add_cmd (char *, enum command_class, - void (*fun) (char *, int), char *, - struct cmd_list_element **); - -extern struct cmd_list_element *add_alias_cmd (char *, char *, - enum command_class, int, - struct cmd_list_element **); - -extern struct cmd_list_element *add_prefix_cmd (char *, enum command_class, - void (*fun) (char *, int), - char *, - struct cmd_list_element **, - char *, int, - struct cmd_list_element **); - -extern struct cmd_list_element *add_abbrev_prefix_cmd (char *, - enum command_class, - void (*fun) (char *, - int), - char *, - struct cmd_list_element - **, char *, int, - struct cmd_list_element - **); - -/* Set the commands corresponding callback. */ - -extern void set_cmd_cfunc (struct cmd_list_element *cmd, - void (*cfunc) (char *args, int from_tty)); - -extern void set_cmd_sfunc (struct cmd_list_element *cmd, - void (*sfunc) (char *args, int from_tty, - struct cmd_list_element * c)); - -extern void set_cmd_completer (struct cmd_list_element *cmd, - char **(*completer) (struct cmd_list_element *self, - char *text, char *word)); - -/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs - around in cmd objects to test the value of the commands sfunc(). */ -extern int cmd_cfunc_eq (struct cmd_list_element *cmd, - void (*cfunc) (char *args, int from_tty)); - -/* Access to the command's local context. */ -extern void set_cmd_context (struct cmd_list_element *cmd, void *context); -extern void *get_cmd_context (struct cmd_list_element *cmd); - -extern struct cmd_list_element *lookup_cmd (char **, - struct cmd_list_element *, char *, - int, int); - -extern struct cmd_list_element *lookup_cmd_1 (char **, - struct cmd_list_element *, - struct cmd_list_element **, - int); - -extern struct cmd_list_element * - deprecate_cmd (struct cmd_list_element *, char * ); - -extern void - deprecated_cmd_warning (char **); - -extern int - lookup_cmd_composition (char *text, - struct cmd_list_element **alias, - struct cmd_list_element **prefix_cmd, - struct cmd_list_element **cmd); - -extern struct cmd_list_element *add_com (char *, enum command_class, - void (*fun) (char *, int), char *); - -extern struct cmd_list_element *add_com_alias (char *, char *, - enum command_class, int); - -extern struct cmd_list_element *add_info (char *, void (*fun) (char *, int), - char *); - -extern struct cmd_list_element *add_info_alias (char *, char *, int); - -extern char **complete_on_cmdlist (struct cmd_list_element *, char *, char *); - -extern char **complete_on_enum (const char *enumlist[], char *, char *); - extern void help_cmd_list (struct cmd_list_element *, enum command_class, char *, int, struct ui_file *); @@ -304,9 +225,6 @@ extern void help_cmd_list (struct cmd_list_element *, enum command_class, extern void help_cmd (char *, struct ui_file *); -extern void help_list (struct cmd_list_element *, char *, - enum command_class, struct ui_file *); - extern void apropos_cmd (struct ui_file *, struct cmd_list_element *, struct re_pattern_buffer *, char *); @@ -320,5 +238,6 @@ extern void not_just_help_class_command (char *arg, int from_tty); extern void print_doc_line (struct ui_file *, char *); +extern const char * const auto_boolean_enums[]; #endif /* !defined (CLI_DECODE_H) */ diff --git a/contrib/gdb-7/gdb/cli/cli-dump.c b/contrib/gdb-7/gdb/cli/cli-dump.c index 4a8b5d13b2..476cd5691d 100644 --- a/contrib/gdb-7/gdb/cli/cli-dump.c +++ b/contrib/gdb-7/gdb/cli/cli-dump.c @@ -1,6 +1,6 @@ /* Dump-to-file commands, for GDB, the GNU debugger. - Copyright (c) 2002, 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. Contributed by Red Hat. @@ -32,6 +32,7 @@ #include "readline/readline.h" #include "gdbcore.h" #include "cli/cli-utils.h" +#include "gdb_bfd.h" #define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE))) @@ -111,12 +112,12 @@ bfd_openr_with_cleanup (const char *filename, const char *target) { bfd *ibfd; - ibfd = bfd_openr (filename, target); + ibfd = gdb_bfd_openr (filename, target); if (ibfd == NULL) error (_("Failed to open %s: %s."), filename, bfd_errmsg (bfd_get_error ())); - make_cleanup_bfd_close (ibfd); + make_cleanup_bfd_unref (ibfd); if (!bfd_check_format (ibfd, bfd_object)) error (_("'%s' is not a recognized file format."), filename); @@ -131,11 +132,11 @@ bfd_openw_with_cleanup (const char *filename, const char *target, if (*mode == 'w') /* Write: create new file */ { - obfd = bfd_openw (filename, target); + obfd = gdb_bfd_openw (filename, target); if (obfd == NULL) error (_("Failed to open %s: %s."), filename, bfd_errmsg (bfd_get_error ())); - make_cleanup_bfd_close (obfd); + make_cleanup_bfd_unref (obfd); if (!bfd_set_format (obfd, bfd_object)) error (_("bfd_openw_with_cleanup: %s."), bfd_errmsg (bfd_get_error ())); } @@ -149,13 +150,13 @@ bfd_openw_with_cleanup (const char *filename, const char *target, return obfd; } -struct cmd_list_element *dump_cmdlist; -struct cmd_list_element *append_cmdlist; -struct cmd_list_element *srec_cmdlist; -struct cmd_list_element *ihex_cmdlist; -struct cmd_list_element *tekhex_cmdlist; -struct cmd_list_element *binary_dump_cmdlist; -struct cmd_list_element *binary_append_cmdlist; +static struct cmd_list_element *dump_cmdlist; +static struct cmd_list_element *append_cmdlist; +static struct cmd_list_element *srec_cmdlist; +static struct cmd_list_element *ihex_cmdlist; +static struct cmd_list_element *tekhex_cmdlist; +static struct cmd_list_element *binary_dump_cmdlist; +static struct cmd_list_element *binary_append_cmdlist; static void dump_command (char *cmd, int from_tty) @@ -485,10 +486,10 @@ restore_section_callback (bfd *ibfd, asection *isec, void *args) if (data->load_offset != 0 || data->load_start != 0 || data->load_end != 0) printf_filtered (" into memory (%s to %s)\n", - paddress (target_gdbarch, + paddress (target_gdbarch (), (unsigned long) sec_start + sec_offset + data->load_offset), - paddress (target_gdbarch, + paddress (target_gdbarch (), (unsigned long) sec_start + sec_offset + data->load_offset + sec_load_count)); else diff --git a/contrib/gdb-7/gdb/cli/cli-dump.h b/contrib/gdb-7/gdb/cli/cli-dump.h index 9ca1d88870..585d4d77b0 100644 --- a/contrib/gdb-7/gdb/cli/cli-dump.h +++ b/contrib/gdb-7/gdb/cli/cli-dump.h @@ -1,6 +1,6 @@ /* Dump-to-file commands, for GDB, the GNU debugger. - Copyright (c) 2001, 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/cli/cli-interp.c b/contrib/gdb-7/gdb/cli/cli-interp.c index 9c44b24070..1003cc73bb 100644 --- a/contrib/gdb-7/gdb/cli/cli-interp.c +++ b/contrib/gdb-7/gdb/cli/cli-interp.c @@ -1,6 +1,6 @@ /* CLI Definitions for GDB, the GNU debugger. - Copyright (c) 2002-2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -19,7 +19,6 @@ #include "defs.h" #include "interps.h" -#include "wrapper.h" #include "event-top.h" #include "ui-out.h" #include "cli-out.h" diff --git a/contrib/gdb-7/gdb/cli/cli-logging.c b/contrib/gdb-7/gdb/cli/cli-logging.c index 0c5bda8797..9f1477dc98 100644 --- a/contrib/gdb-7/gdb/cli/cli-logging.c +++ b/contrib/gdb-7/gdb/cli/cli-logging.c @@ -1,6 +1,6 @@ /* Command-line output logging for GDB, the GNU debugger. - Copyright (c) 2003-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -20,6 +20,7 @@ #include "defs.h" #include "gdbcmd.h" #include "ui-out.h" +#include "interps.h" #include "gdb_assert.h" #include "gdb_string.h" @@ -115,11 +116,17 @@ set_logging_redirect (char *args, int from_tty, struct cmd_list_element *c) logging_filename); } - gdb_stdout = output; - gdb_stderr = output; - gdb_stdlog = output; - gdb_stdtarg = output; - gdb_stdtargerr = output; + /* Give the current interpreter a chance to do anything special that + it might need for logging, such as updating other channels. */ + if (current_interp_set_logging (1, output, NULL) == 0) + { + gdb_stdout = output; + gdb_stdlog = output; + gdb_stderr = output; + gdb_stdtarg = output; + gdb_stdtargerr = output; + } + logging_no_redirect_file = new_logging_no_redirect_file; /* There is a former output pushed on the ui_out_redirect stack. We @@ -147,19 +154,25 @@ show_logging_redirect (struct ui_file *file, int from_tty, static void pop_output_files (void) { - /* Only delete one of the files -- they are all set to the same - value. */ - ui_file_delete (gdb_stdout); if (logging_no_redirect_file) { ui_file_delete (logging_no_redirect_file); logging_no_redirect_file = NULL; } - gdb_stdout = saved_output.out; - gdb_stderr = saved_output.err; - gdb_stdlog = saved_output.log; - gdb_stdtarg = saved_output.targ; - gdb_stdtargerr = saved_output.targ; + + if (current_interp_set_logging (0, NULL, NULL) == 0) + { + /* Only delete one of the files -- they are all set to the same + value. */ + ui_file_delete (gdb_stdout); + + gdb_stdout = saved_output.out; + gdb_stderr = saved_output.err; + gdb_stdlog = saved_output.log; + gdb_stdtarg = saved_output.targ; + gdb_stdtargerr = saved_output.targ; + } + saved_output.out = NULL; saved_output.err = NULL; saved_output.log = NULL; @@ -175,6 +188,7 @@ handle_redirections (int from_tty) { struct cleanup *cleanups; struct ui_file *output; + struct ui_file *no_redirect_file = NULL; if (saved_filename != NULL) { @@ -191,7 +205,7 @@ handle_redirections (int from_tty) /* Redirects everything to gdb_stdout while this is running. */ if (!logging_redirect) { - struct ui_file *no_redirect_file = output; + no_redirect_file = output; output = tee_file_new (gdb_stdout, 0, no_redirect_file, 0); if (output == NULL) @@ -220,14 +234,22 @@ handle_redirections (int from_tty) saved_output.targ = gdb_stdtarg; saved_output.targerr = gdb_stdtargerr; - gdb_stdout = output; - gdb_stderr = output; - gdb_stdlog = output; - gdb_stdtarg = output; - gdb_stdtargerr = output; + /* Let the interpreter do anything it needs. */ + if (current_interp_set_logging (1, output, no_redirect_file) == 0) + { + gdb_stdout = output; + gdb_stdlog = output; + gdb_stderr = output; + gdb_stdtarg = output; + gdb_stdtargerr = output; + } - if (ui_out_redirect (current_uiout, output) < 0) - warning (_("Current output protocol does not support redirection")); + /* Don't do the redirect for MI, it confuses MI's ui-out scheme. */ + if (!ui_out_is_mi_like_p (current_uiout)) + { + if (ui_out_redirect (current_uiout, output) < 0) + warning (_("Current output protocol does not support redirection")); + } } static void diff --git a/contrib/gdb-7/gdb/cli/cli-script.c b/contrib/gdb-7/gdb/cli/cli-script.c index c8da8c83e1..a96886685b 100644 --- a/contrib/gdb-7/gdb/cli/cli-script.c +++ b/contrib/gdb-7/gdb/cli/cli-script.c @@ -1,6 +1,6 @@ /* GDB CLI command scripting. - Copyright (c) 1986-2002, 2004-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -314,7 +314,7 @@ execute_user_command (struct cmd_list_element *c, char *args) struct cleanup *old_chain; enum command_control_type ret; static int user_call_depth = 0; - extern int max_user_call_depth; + extern unsigned int max_user_call_depth; cmdlines = c->user_commands; if (cmdlines == 0) @@ -441,9 +441,10 @@ execute_control_command (struct command_line *cmd) case while_control: { - char *buffer = alloca (strlen (cmd->line) + 7); + int len = strlen (cmd->line) + 7; + char *buffer = alloca (len); - sprintf (buffer, "while %s", cmd->line); + xsnprintf (buffer, len, "while %s", cmd->line); print_command_trace (buffer); /* Parse the loop control expression for the while statement. */ @@ -509,9 +510,10 @@ execute_control_command (struct command_line *cmd) case if_control: { - char *buffer = alloca (strlen (cmd->line) + 4); + int len = strlen (cmd->line) + 4; + char *buffer = alloca (len); - sprintf (buffer, "if %s", cmd->line); + xsnprintf (buffer, len, "if %s", cmd->line); print_command_trace (buffer); new_line = insert_args (cmd->line); @@ -596,7 +598,7 @@ execute_control_command_untraced (struct command_line *cmd) /* "while" command support. Executes a body of statements while the loop condition is nonzero. */ -void +static void while_command (char *arg, int from_tty) { struct command_line *command = NULL; @@ -620,7 +622,7 @@ while_command (char *arg, int from_tty) /* "if" command support. Execute either the true or false arm depending on the value of the if conditional. */ -void +static void if_command (char *arg, int from_tty) { struct command_line *command = NULL; @@ -1178,6 +1180,12 @@ recurse_read_control_structure (char * (*read_next_line_func) (void), return ret; } +static void +restore_interp (void *arg) +{ + interp_set_temp (interp_name ((struct interp *)arg)); +} + /* Read lines from the input stream and accumulate them in a chain of struct command_line's, which is then returned. For input from a terminal, the special command "end" is used to mark the end of the @@ -1210,8 +1218,21 @@ read_command_lines (char *prompt_arg, int from_tty, int parse_commands, } } - head = read_command_lines_1 (read_next_line, parse_commands, - validator, closure); + + /* Reading commands assumes the CLI behavior, so temporarily + override the current interpreter with CLI. */ + if (current_interp_named_p (INTERP_CONSOLE)) + head = read_command_lines_1 (read_next_line, parse_commands, + validator, closure); + else + { + struct interp *old_interp = interp_set_temp (INTERP_CONSOLE); + struct cleanup *old_chain = make_cleanup (restore_interp, old_interp); + + head = read_command_lines_1 (read_next_line, parse_commands, + validator, closure); + do_cleanups (old_chain); + } if (deprecated_readline_end_hook && from_tty && input_from_terminal_p ()) { @@ -1427,7 +1448,7 @@ user_defined_command (char *ignore, int from_tty) { } -void +static void define_command (char *comname, int from_tty) { #define MAX_TMPBUF 128 @@ -1510,7 +1531,8 @@ define_command (char *comname, int from_tty) if (isupper (*tem)) *tem = tolower (*tem); - sprintf (tmpbuf, "Type commands for definition of \"%s\".", comfull); + xsnprintf (tmpbuf, sizeof (tmpbuf), + "Type commands for definition of \"%s\".", comfull); cmds = read_command_lines (tmpbuf, from_tty, 1, 0, 0); if (c && c->class == class_user) @@ -1543,7 +1565,7 @@ define_command (char *comname, int from_tty) } } -void +static void document_command (char *comname, int from_tty) { struct command_line *doclines; @@ -1560,7 +1582,8 @@ document_command (char *comname, int from_tty) if (c->class != class_user) error (_("Command \"%s\" is built-in."), comfull); - sprintf (tmpbuf, "Type documentation for \"%s\".", comfull); + xsnprintf (tmpbuf, sizeof (tmpbuf), "Type documentation for \"%s\".", + comfull); doclines = read_command_lines (tmpbuf, from_tty, 0, 0, 0); if (c->doc) @@ -1614,11 +1637,9 @@ script_from_file (FILE *stream, const char *file) if (stream == NULL) internal_error (__FILE__, __LINE__, _("called with NULL file pointer!")); - old_cleanups = make_cleanup_fclose (stream); - old_lines.old_line = source_line_number; old_lines.old_file = source_file_name; - make_cleanup (source_cleanup_lines, &old_lines); + old_cleanups = make_cleanup (source_cleanup_lines, &old_lines); source_line_number = 0; source_file_name = file; /* This will get set every time we read a line. So it won't stay "" @@ -1679,3 +1700,34 @@ show_user_1 (struct cmd_list_element *c, char *prefix, char *name, fputs_filtered ("\n", stream); } + + +initialize_file_ftype _initialize_cli_script; + +void +_initialize_cli_script (void) +{ + add_com ("document", class_support, document_command, _("\ +Document a user-defined command.\n\ +Give command name as argument. Give documentation on following lines.\n\ +End with a line of just \"end\".")); + add_com ("define", class_support, define_command, _("\ +Define a new command name. Command name is argument.\n\ +Definition appears on following lines, one command per line.\n\ +End with a line of just \"end\".\n\ +Use the \"document\" command to give documentation for the new command.\n\ +Commands defined in this way may have up to ten arguments.")); + + add_com ("while", class_support, while_command, _("\ +Execute nested commands WHILE the conditional expression is non zero.\n\ +The conditional expression must follow the word `while' and must in turn be\n\ +followed by a new line. The nested commands must be entered one per line,\n\ +and should be terminated by the word `end'.")); + + add_com ("if", class_support, if_command, _("\ +Execute nested commands once IF the conditional expression is non zero.\n\ +The conditional expression must follow the word `if' and must in turn be\n\ +followed by a new line. The nested commands must be entered one per line,\n\ +and should be terminated by the word 'else' or `end'. If an else clause\n\ +is used, the same rules apply to its nested commands as to the first ones.")); +} diff --git a/contrib/gdb-7/gdb/cli/cli-script.h b/contrib/gdb-7/gdb/cli/cli-script.h index 999c4e8a92..d02cb36446 100644 --- a/contrib/gdb-7/gdb/cli/cli-script.h +++ b/contrib/gdb-7/gdb/cli/cli-script.h @@ -1,5 +1,5 @@ /* Header file for GDB CLI command implementation library. - Copyright (c) 2000, 2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 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 @@ -25,14 +25,6 @@ struct cmd_list_element; extern void script_from_file (FILE *stream, const char *file); -extern void document_command (char *, int); - -extern void define_command (char *, int); - -extern void while_command (char *arg, int from_tty); - -extern void if_command (char *arg, int from_tty); - extern void show_user_1 (struct cmd_list_element *c, char *prefix, char *name, struct ui_file *stream); @@ -52,7 +44,8 @@ extern void print_command_lines (struct ui_out *, extern struct command_line * copy_command_lines (struct command_line *cmds); -struct cleanup *make_cleanup_free_command_lines (struct command_line **arg); +extern struct cleanup * + make_cleanup_free_command_lines (struct command_line **arg); /* Exported to gdb/infrun.c */ diff --git a/contrib/gdb-7/gdb/cli/cli-setshow.c b/contrib/gdb-7/gdb/cli/cli-setshow.c index 14fef7c1ec..20ae72cc8a 100644 --- a/contrib/gdb-7/gdb/cli/cli-setshow.c +++ b/contrib/gdb-7/gdb/cli/cli-setshow.c @@ -1,6 +1,6 @@ /* Handle set and show GDB commands. - Copyright (c) 2000-2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 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 @@ -21,6 +21,7 @@ #include #include "gdb_string.h" #include "arch-utils.h" +#include "observer.h" #include "ui-out.h" @@ -32,6 +33,21 @@ static int parse_binary_operation (char *); +/* Return true if the change of command parameter should be notified. */ + +static int +notify_command_param_changed_p (int param_changed, struct cmd_list_element *c) +{ + if (param_changed == 0) + return 0; + + if (c->class == class_maintenance || c->class == class_deprecated + || c->class == class_obscure) + return 0; + + return 1; +} + static enum auto_boolean parse_auto_binary_operation (const char *arg) @@ -116,84 +132,95 @@ deprecated_show_value_hack (struct ui_file *ignore_file, } } -/* Do a "set" or "show" command. ARG is NULL if no argument, or the +/* Do a "set" command. ARG is NULL if no argument, or the text of the argument, and FROM_TTY is nonzero if this command is being entered directly by the user (i.e. these are just like any other command). C is the command list element for the command. */ void -do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) +do_set_command (char *arg, int from_tty, struct cmd_list_element *c) { - struct ui_out *uiout = current_uiout; + /* A flag to indicate the option is changed or not. */ + int option_changed = 0; + + gdb_assert (c->type == set_cmd); - if (c->type == set_cmd) + switch (c->var_type) { - switch (c->var_type) - { - case var_string: + case var_string: + { + char *new; + char *p; + char *q; + int ch; + + if (arg == NULL) + arg = ""; + new = (char *) xmalloc (strlen (arg) + 2); + p = arg; + q = new; + while ((ch = *p++) != '\000') { - char *new; - char *p; - char *q; - int ch; - - if (arg == NULL) - arg = ""; - new = (char *) xmalloc (strlen (arg) + 2); - p = arg; - q = new; - while ((ch = *p++) != '\000') + if (ch == '\\') { - if (ch == '\\') - { - /* \ at end of argument is used after spaces - so they won't be lost. */ - /* This is obsolete now that we no longer strip - trailing whitespace and actually, the backslash - didn't get here in my test, readline or - something did something funky with a backslash - right before a newline. */ - if (*p == 0) - break; - ch = parse_escape (get_current_arch (), &p); - if (ch == 0) - break; /* C loses */ - else if (ch > 0) - *q++ = ch; - } - else + /* \ at end of argument is used after spaces + so they won't be lost. */ + /* This is obsolete now that we no longer strip + trailing whitespace and actually, the backslash + didn't get here in my test, readline or + something did something funky with a backslash + right before a newline. */ + if (*p == 0) + break; + ch = parse_escape (get_current_arch (), &p); + if (ch == 0) + break; /* C loses */ + else if (ch > 0) *q++ = ch; } + else + *q++ = ch; + } #if 0 - if (*(p - 1) != '\\') - *q++ = ' '; + if (*(p - 1) != '\\') + *q++ = ' '; #endif - *q++ = '\0'; - new = (char *) xrealloc (new, q - new); - if (*(char **) c->var != NULL) - xfree (*(char **) c->var); + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, new) != 0) + { + xfree (*(char **) c->var); *(char **) c->var = new; + + option_changed = 1; } - break; - case var_string_noescape: - if (arg == NULL) - arg = ""; - if (*(char **) c->var != NULL) - xfree (*(char **) c->var); - *(char **) c->var = xstrdup (arg); - break; - case var_optional_filename: - if (arg == NULL) - arg = ""; - if (*(char **) c->var != NULL) - xfree (*(char **) c->var); + else + xfree (new); + } + break; + case var_string_noescape: + if (arg == NULL) + arg = ""; + + if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0) + { + xfree (*(char **) c->var); *(char **) c->var = xstrdup (arg); - break; - case var_filename: - if (arg == NULL) - error_no_arg (_("filename to set it to.")); - if (*(char **) c->var != NULL) - xfree (*(char **) c->var); + + option_changed = 1; + } + break; + case var_filename: + if (arg == NULL) + error_no_arg (_("filename to set it to.")); + /* FALLTHROUGH */ + case var_optional_filename: + { + char *val = NULL; + + if (arg != NULL) { /* Clear trailing whitespace of filename. */ char *ptr = arg + strlen (arg) - 1; @@ -201,209 +228,409 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) ptr--; *(ptr + 1) = '\0'; + + val = tilde_expand (arg); } - *(char **) c->var = tilde_expand (arg); - break; - case var_boolean: - *(int *) c->var = parse_binary_operation (arg); - break; - case var_auto_boolean: - *(enum auto_boolean *) c->var = parse_auto_binary_operation (arg); - break; - case var_uinteger: - if (arg == NULL) - error_no_arg (_("integer to set it to.")); - *(unsigned int *) c->var = parse_and_eval_long (arg); - if (*(unsigned int *) c->var == 0) - *(unsigned int *) c->var = UINT_MAX; - break; - case var_integer: + else + val = xstrdup (""); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, val) != 0) { - unsigned int val; - - if (arg == NULL) - error_no_arg (_("integer to set it to.")); - val = parse_and_eval_long (arg); - if (val == 0) - *(int *) c->var = INT_MAX; - else if (val >= INT_MAX) - error (_("integer %u out of range"), val); - else - *(int *) c->var = val; - break; + xfree (*(char **) c->var); + *(char **) c->var = val; + + option_changed = 1; } - case var_zinteger: - if (arg == NULL) - error_no_arg (_("integer to set it to.")); - *(int *) c->var = parse_and_eval_long (arg); - break; - case var_zuinteger: - if (arg == NULL) - error_no_arg (_("integer to set it to.")); - *(unsigned int *) c->var = parse_and_eval_long (arg); - break; - case var_enum: + else + xfree (val); + } + break; + case var_boolean: + { + int val = parse_binary_operation (arg); + + if (val != *(int *) c->var) + { + *(int *) c->var = val; + + option_changed = 1; + } + } + break; + case var_auto_boolean: + { + enum auto_boolean val = parse_auto_binary_operation (arg); + + if (*(enum auto_boolean *) c->var != val) + { + *(enum auto_boolean *) c->var = val; + + option_changed = 1; + } + } + break; + case var_uinteger: + case var_zuinteger: + { + LONGEST val; + + if (arg == NULL) + error_no_arg (_("integer to set it to.")); + val = parse_and_eval_long (arg); + + if (c->var_type == var_uinteger && val == 0) + val = UINT_MAX; + else if (val < 0 + /* For var_uinteger, don't let the user set the value + to UINT_MAX directly, as that exposes an + implementation detail to the user interface. */ + || (c->var_type == var_uinteger && val >= UINT_MAX) + || (c->var_type == var_zuinteger && val > UINT_MAX)) + error (_("integer %s out of range"), plongest (val)); + + if (*(unsigned int *) c->var != val) + { + *(unsigned int *) c->var = val; + + option_changed = 1; + } + } + break; + case var_integer: + case var_zinteger: + { + LONGEST val; + + if (arg == NULL) + error_no_arg (_("integer to set it to.")); + val = parse_and_eval_long (arg); + + if (val == 0 && c->var_type == var_integer) + val = INT_MAX; + else if (val < INT_MIN + /* For var_integer, don't let the user set the value + to INT_MAX directly, as that exposes an + implementation detail to the user interface. */ + || (c->var_type == var_integer && val >= INT_MAX) + || (c->var_type == var_zinteger && val > INT_MAX)) + error (_("integer %s out of range"), plongest (val)); + + if (*(int *) c->var != val) + { + *(int *) c->var = val; + + option_changed = 1; + } + break; + } + case var_enum: + { + int i; + int len; + int nmatches; + const char *match = NULL; + char *p; + + /* If no argument was supplied, print an informative error + message. */ + if (arg == NULL) { - int i; - int len; - int nmatches; - const char *match = NULL; - char *p; - - /* If no argument was supplied, print an informative error - message. */ - if (arg == NULL) + char *msg; + int msg_len = 0; + + for (i = 0; c->enums[i]; i++) + msg_len += strlen (c->enums[i]) + 2; + + msg = xmalloc (msg_len); + *msg = '\0'; + make_cleanup (xfree, msg); + + for (i = 0; c->enums[i]; i++) { - char *msg; - int msg_len = 0; - - for (i = 0; c->enums[i]; i++) - msg_len += strlen (c->enums[i]) + 2; - - msg = xmalloc (msg_len); - *msg = '\0'; - make_cleanup (xfree, msg); - - for (i = 0; c->enums[i]; i++) - { - if (i != 0) - strcat (msg, ", "); - strcat (msg, c->enums[i]); - } - error (_("Requires an argument. Valid arguments are %s."), - msg); + if (i != 0) + strcat (msg, ", "); + strcat (msg, c->enums[i]); } + error (_("Requires an argument. Valid arguments are %s."), + msg); + } - p = strchr (arg, ' '); + p = strchr (arg, ' '); - if (p) - len = p - arg; - else - len = strlen (arg); + if (p) + len = p - arg; + else + len = strlen (arg); - nmatches = 0; - for (i = 0; c->enums[i]; i++) - if (strncmp (arg, c->enums[i], len) == 0) + nmatches = 0; + for (i = 0; c->enums[i]; i++) + if (strncmp (arg, c->enums[i], len) == 0) + { + if (c->enums[i][len] == '\0') { - if (c->enums[i][len] == '\0') - { - match = c->enums[i]; - nmatches = 1; - break; /* Exact match. */ - } - else - { - match = c->enums[i]; - nmatches++; - } + match = c->enums[i]; + nmatches = 1; + break; /* Exact match. */ } + else + { + match = c->enums[i]; + nmatches++; + } + } - if (nmatches <= 0) - error (_("Undefined item: \"%s\"."), arg); + if (nmatches <= 0) + error (_("Undefined item: \"%s\"."), arg); - if (nmatches > 1) - error (_("Ambiguous item \"%s\"."), arg); + if (nmatches > 1) + error (_("Ambiguous item \"%s\"."), arg); + if (*(const char **) c->var != match) + { *(const char **) c->var = match; + + option_changed = 1; } - break; - default: - error (_("gdb internal error: bad var_type in do_setshow_command")); - } + } + break; + case var_zuinteger_unlimited: + { + LONGEST val; + + if (arg == NULL) + error_no_arg (_("integer to set it to.")); + val = parse_and_eval_long (arg); + + if (val > INT_MAX) + error (_("integer %s out of range"), plongest (val)); + else if (val < -1) + error (_("only -1 is allowed to set as unlimited")); + + if (*(int *) c->var != val) + { + *(int *) c->var = val; + option_changed = 1; + } + } + break; + default: + error (_("gdb internal error: bad var_type in do_setshow_command")); } - else if (c->type == show_cmd) + c->func (c, NULL, from_tty); + if (deprecated_set_hook) + deprecated_set_hook (c); + + if (notify_command_param_changed_p (option_changed, c)) { - struct cleanup *old_chain; - struct ui_stream *stb; + char *name, *cp; + struct cmd_list_element **cmds; + struct cmd_list_element *p; + int i; + int length = 0; + + /* Compute the whole multi-word command options. If user types command + 'set foo bar baz on', c->name is 'baz', and GDB can't pass "bar" to + command option change notification, because it is confusing. We can + trace back through field 'prefix' to compute the whole options, + and pass "foo bar baz" to notification. */ + + for (i = 0, p = c; p != NULL; i++) + { + length += strlen (p->name); + length++; + + p = p->prefix; + } + cp = name = xmalloc (length); + cmds = xmalloc (sizeof (struct cmd_list_element *) * i); + + /* Track back through filed 'prefix' and cache them in CMDS. */ + for (i = 0, p = c; p != NULL; i++) + { + cmds[i] = p; + p = p->prefix; + } + + /* Don't trigger any observer notification if prefixlist is not + setlist. */ + i--; + if (cmds[i]->prefixlist != &setlist) + { + xfree (cmds); + xfree (name); - stb = ui_out_stream_new (uiout); - old_chain = make_cleanup_ui_out_stream_delete (stb); + return; + } + /* Traverse them in the reversed order, and copy their names into + NAME. */ + for (i--; i >= 0; i--) + { + memcpy (cp, cmds[i]->name, strlen (cmds[i]->name)); + cp += strlen (cmds[i]->name); + + if (i != 0) + { + cp[0] = ' '; + cp++; + } + } + cp[0] = 0; - /* Possibly call the pre hook. */ - if (c->pre_show_hook) - (c->pre_show_hook) (c); + xfree (cmds); switch (c->var_type) { case var_string: - if (*(char **) c->var) - fputstr_filtered (*(char **) c->var, '"', stb->stream); - break; case var_string_noescape: - case var_optional_filename: case var_filename: + case var_optional_filename: case var_enum: - if (*(char **) c->var) - fputs_filtered (*(char **) c->var, stb->stream); + observer_notify_command_param_changed (name, *(char **) c->var); break; case var_boolean: - fputs_filtered (*(int *) c->var ? "on" : "off", stb->stream); + { + char *opt = *(int *) c->var ? "on" : "off"; + + observer_notify_command_param_changed (name, opt); + } break; case var_auto_boolean: - switch (*(enum auto_boolean*) c->var) - { - case AUTO_BOOLEAN_TRUE: - fputs_filtered ("on", stb->stream); - break; - case AUTO_BOOLEAN_FALSE: - fputs_filtered ("off", stb->stream); - break; - case AUTO_BOOLEAN_AUTO: - fputs_filtered ("auto", stb->stream); - break; - default: - internal_error (__FILE__, __LINE__, - _("do_setshow_command: " - "invalid var_auto_boolean")); - break; - } + { + const char *s = auto_boolean_enums[*(enum auto_boolean *) c->var]; + + observer_notify_command_param_changed (name, s); + } break; case var_uinteger: case var_zuinteger: - if (c->var_type == var_uinteger - && *(unsigned int *) c->var == UINT_MAX) - fputs_filtered ("unlimited", stb->stream); - else - fprintf_filtered (stb->stream, "%u", *(unsigned int *) c->var); + { + char s[64]; + + xsnprintf (s, sizeof s, "%u", *(unsigned int *) c->var); + observer_notify_command_param_changed (name, s); + } break; case var_integer: case var_zinteger: - if (c->var_type == var_integer - && *(int *) c->var == INT_MAX) - fputs_filtered ("unlimited", stb->stream); - else - fprintf_filtered (stb->stream, "%d", *(int *) c->var); - break; + case var_zuinteger_unlimited: + { + char s[64]; - default: - error (_("gdb internal error: bad var_type in do_setshow_command")); + xsnprintf (s, sizeof s, "%d", *(int *) c->var); + observer_notify_command_param_changed (name, s); + } + break; } + xfree (name); + } +} +/* Do a "show" command. ARG is NULL if no argument, or the + text of the argument, and FROM_TTY is nonzero if this command is + being entered directly by the user (i.e. these are just like any + other command). C is the command list element for the command. */ - /* FIXME: cagney/2005-02-10: Need to split this in half: code to - convert the value into a string (esentially the above); and - code to print the value out. For the latter there should be - MI and CLI specific versions. */ +void +do_show_command (char *arg, int from_tty, struct cmd_list_element *c) +{ + struct ui_out *uiout = current_uiout; + struct cleanup *old_chain; + struct ui_file *stb; - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_stream (uiout, "value", stb); - else - { - char *value = ui_file_xstrdup (stb->stream, NULL); + gdb_assert (c->type == show_cmd); - make_cleanup (xfree, value); - if (c->show_value_func != NULL) - c->show_value_func (gdb_stdout, from_tty, c, value); - else - deprecated_show_value_hack (gdb_stdout, from_tty, c, value); + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); + + /* Possibly call the pre hook. */ + if (c->pre_show_hook) + (c->pre_show_hook) (c); + + switch (c->var_type) + { + case var_string: + if (*(char **) c->var) + fputstr_filtered (*(char **) c->var, '"', stb); + break; + case var_string_noescape: + case var_optional_filename: + case var_filename: + case var_enum: + if (*(char **) c->var) + fputs_filtered (*(char **) c->var, stb); + break; + case var_boolean: + fputs_filtered (*(int *) c->var ? "on" : "off", stb); + break; + case var_auto_boolean: + switch (*(enum auto_boolean*) c->var) + { + case AUTO_BOOLEAN_TRUE: + fputs_filtered ("on", stb); + break; + case AUTO_BOOLEAN_FALSE: + fputs_filtered ("off", stb); + break; + case AUTO_BOOLEAN_AUTO: + fputs_filtered ("auto", stb); + break; + default: + internal_error (__FILE__, __LINE__, + _("do_show_command: " + "invalid var_auto_boolean")); + break; } - do_cleanups (old_chain); + break; + case var_uinteger: + case var_zuinteger: + if (c->var_type == var_uinteger + && *(unsigned int *) c->var == UINT_MAX) + fputs_filtered ("unlimited", stb); + else + fprintf_filtered (stb, "%u", *(unsigned int *) c->var); + break; + case var_integer: + case var_zinteger: + if (c->var_type == var_integer + && *(int *) c->var == INT_MAX) + fputs_filtered ("unlimited", stb); + else + fprintf_filtered (stb, "%d", *(int *) c->var); + break; + case var_zuinteger_unlimited: + { + if (*(int *) c->var == -1) + fputs_filtered ("unlimited", stb); + else + fprintf_filtered (stb, "%d", *(int *) c->var); + } + break; + default: + error (_("gdb internal error: bad var_type in do_show_command")); } + + + /* FIXME: cagney/2005-02-10: Need to split this in half: code to + convert the value into a string (esentially the above); and + code to print the value out. For the latter there should be + MI and CLI specific versions. */ + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_stream (uiout, "value", stb); else - error (_("gdb internal error: bad cmd_type in do_setshow_command")); + { + char *value = ui_file_xstrdup (stb, NULL); + + make_cleanup (xfree, value); + if (c->show_value_func != NULL) + c->show_value_func (gdb_stdout, from_tty, c, value); + else + deprecated_show_value_hack (gdb_stdout, from_tty, c, value); + } + do_cleanups (old_chain); + c->func (c, NULL, from_tty); - if (c->type == set_cmd && deprecated_set_hook) - deprecated_set_hook (c); } /* Show all the settings in a list of show commands. */ @@ -442,7 +669,7 @@ cmd_show_list (struct cmd_list_element *list, int from_tty, char *prefix) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ diff --git a/contrib/gdb-7/gdb/cli/cli-setshow.h b/contrib/gdb-7/gdb/cli/cli-setshow.h index cb8d2c5b42..079b9dae7e 100644 --- a/contrib/gdb-7/gdb/cli/cli-setshow.h +++ b/contrib/gdb-7/gdb/cli/cli-setshow.h @@ -1,5 +1,5 @@ /* Header file for GDB CLI set and show commands implementation. - Copyright (c) 2000-2001, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 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 @@ -21,12 +21,10 @@ struct cmd_list_element; /* Exported to cli/cli-cmds.c and gdb/top.c */ -/* Do a "set" or "show" command. ARG is NULL if no argument, or the - text of the argument, and FROM_TTY is nonzero if this command is - being entered directly by the user (i.e. these are just like any - other command). C is the command list element for the command. */ -extern void do_setshow_command (char *arg, int from_tty, - struct cmd_list_element *c); +extern void do_set_command (char *arg, int from_tty, + struct cmd_list_element *c); +extern void do_show_command (char *arg, int from_tty, + struct cmd_list_element *c); /* Exported to cli/cli-cmds.c and gdb/top.c, language.c and valprint.c */ diff --git a/contrib/gdb-7/gdb/cli/cli-utils.c b/contrib/gdb-7/gdb/cli/cli-utils.c index a7b27187ec..f74e6b1f3f 100644 --- a/contrib/gdb-7/gdb/cli/cli-utils.c +++ b/contrib/gdb-7/gdb/cli/cli-utils.c @@ -1,6 +1,6 @@ /* CLI utilities. - Copyright (c) 2011-2012 Free Software Foundation, Inc. + Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -223,10 +223,22 @@ skip_spaces (char *chp) return chp; } +/* A const-correct version of the above. */ + +const char * +skip_spaces_const (const char *chp) +{ + if (chp == NULL) + return NULL; + while (*chp && isspace (*chp)) + chp++; + return chp; +} + /* See documentation in cli-utils.h. */ -char * -skip_to_space (char *chp) +const char * +skip_to_space_const (const char *chp) { if (chp == NULL) return NULL; @@ -245,3 +257,46 @@ remove_trailing_whitespace (const char *start, char *s) return s; } + +/* See documentation in cli-utils.h. */ + +char * +extract_arg (char **arg) +{ + char *result, *copy; + + if (!*arg) + return NULL; + + /* Find the start of the argument. */ + *arg = skip_spaces (*arg); + if (!**arg) + return NULL; + result = *arg; + + /* Find the end of the argument. */ + *arg = skip_to_space (*arg + 1); + + if (result == *arg) + return NULL; + + copy = xmalloc (*arg - result + 1); + memcpy (copy, result, *arg - result); + copy[*arg - result] = '\0'; + + return copy; +} + +/* See documentation in cli-utils.h. */ + +int +check_for_argument (char **str, char *arg, int arg_len) +{ + if (strncmp (*str, arg, arg_len) == 0 + && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len]))) + { + *str += arg_len; + return 1; + } + return 0; +} diff --git a/contrib/gdb-7/gdb/cli/cli-utils.h b/contrib/gdb-7/gdb/cli/cli-utils.h index e23c7d82b9..152fb89671 100644 --- a/contrib/gdb-7/gdb/cli/cli-utils.h +++ b/contrib/gdb-7/gdb/cli/cli-utils.h @@ -1,6 +1,6 @@ /* CLI utilities. - Copyright (c) 2011-2012 Free Software Foundation, Inc. + Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -94,13 +94,34 @@ extern int number_is_in_list (char *list, int number); extern char *skip_spaces (char *inp); +/* A const-correct version of the above. */ + +extern const char *skip_spaces_const (const char *inp); + /* Skip leading non-whitespace characters in INP, returning an updated pointer. If INP is NULL, return NULL. */ -extern char *skip_to_space (char *inp); +#define skip_to_space(INP) ((char *) skip_to_space_const (INP)) + +/* A const-correct version of the above. */ + +extern const char *skip_to_space_const (const char *inp); /* Reverse S to the last non-whitespace character without skipping past START. */ extern char *remove_trailing_whitespace (const char *start, char *s); + +/* A helper function to extract an argument from *ARG. An argument is + delimited by whitespace. The return value is either NULL if no + argument was found, or an xmalloc'd string. */ + +extern char *extract_arg (char **arg); + +/* A helper function that looks for an argument at the start of a + string. The argument must also either be at the end of the string, + or be followed by whitespace. Returns 1 if it finds the argument, + 0 otherwise. If the argument is found, it updates *STR. */ +extern int check_for_argument (char **str, char *arg, int arg_len); + #endif /* CLI_UTILS_H */ diff --git a/contrib/gdb-7/gdb/coff-pe-read.c b/contrib/gdb-7/gdb/coff-pe-read.c index 66c7c82e82..4be349d1ff 100644 --- a/contrib/gdb-7/gdb/coff-pe-read.c +++ b/contrib/gdb-7/gdb/coff-pe-read.c @@ -2,7 +2,7 @@ convert to internal format, for GDB. Used as a last resort if no debugging symbols recognized. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -21,18 +21,31 @@ Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */ +#include "defs.h" + #include "coff-pe-read.h" -#include "defs.h" #include "bfd.h" #include "gdbtypes.h" +#include "command.h" +#include "gdbcmd.h" #include "symtab.h" #include "symfile.h" #include "objfiles.h" +#include "common/common-utils.h" +#include "coff/internal.h" + +#include /* Internal section information */ +/* Coff PE read debugging flag: + default value is 0, + value 1 outputs problems encountered while parsing PE file, + value above 1 also lists all generated minimal symbols. */ +static unsigned int debug_coff_pe_read; + struct read_pe_section_data { CORE_ADDR vma_offset; /* Offset to loaded address of section. */ @@ -40,8 +53,12 @@ struct read_pe_section_data unsigned long rva_end; /* End offset within the pe. */ enum minimal_symbol_type ms_type; /* Type to assign symbols in section. */ + char *section_name; /* Recorded section name. */ }; +#define IMAGE_SCN_CNT_CODE 0x20 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x40 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x80 #define PE_SECTION_INDEX_TEXT 0 #define PE_SECTION_INDEX_DATA 1 #define PE_SECTION_INDEX_BSS 2 @@ -76,13 +93,41 @@ read_pe_section_index (const char *section_name) } } +/* Get the index of the named section in our own full arrayi. + text, data and bss in that order. Return PE_SECTION_INDEX_INVALID + if passed an unrecognised section name. */ + +static int +get_pe_section_index (const char *section_name, + struct read_pe_section_data *sections, + int nb_sections) +{ + int i; + + for (i = 0; i < nb_sections; i++) + if (strcmp (sections[i].section_name, section_name) == 0) + return i; + return PE_SECTION_INDEX_INVALID; +} + +/* Structure used by get_section_vmas function below + to access section_data array and the size of the array + stored in nb_sections field. */ +struct pe_sections_info +{ + int nb_sections; + struct read_pe_section_data *sections; +}; + /* Record the virtual memory address of a section. */ static void get_section_vmas (bfd *abfd, asection *sectp, void *context) { - struct read_pe_section_data *sections = context; - int sectix = read_pe_section_index (sectp->name); + struct pe_sections_info *data = context; + struct read_pe_section_data *sections = data->sections; + int sectix = get_pe_section_index (sectp->name, sections, + data->nb_sections); if (sectix != PE_SECTION_INDEX_INVALID) { @@ -94,58 +139,147 @@ get_section_vmas (bfd *abfd, asection *sectp, void *context) } } -/* Create a minimal symbol entry for an exported symbol. */ +/* Create a minimal symbol entry for an exported symbol. + SYM_NAME contains the exported name or NULL if exported by ordinal, + FUNC_RVA contains the Relative Virtual Address of the symbol, + ORDINAL is the ordinal index value of the symbol, + SECTION_DATA contains information about the section in which the + symbol is declared, + DLL_NAME is the internal name of the DLL file, + OBJFILE is the objfile struct of DLL_NAME. */ static void -add_pe_exported_sym (char *sym_name, +add_pe_exported_sym (const char *sym_name, unsigned long func_rva, + int ordinal, const struct read_pe_section_data *section_data, const char *dll_name, struct objfile *objfile) { + char *qualified_name, *bare_name; /* Add the stored offset to get the loaded address of the symbol. */ - CORE_ADDR vma = func_rva + section_data->vma_offset; - - char *qualified_name = 0; int dll_name_len = strlen (dll_name); /* Generate a (hopefully unique) qualified name using the first part of the dll name, e.g. KERNEL32!AddAtomA. This matches the style used by windbg from the "Microsoft Debugging Tools for Windows". */ - qualified_name = xmalloc (dll_name_len + strlen (sym_name) + 2); + if (sym_name == NULL || *sym_name == '\0') + bare_name = xstrprintf ("#%d", ordinal); + else + bare_name = xstrdup (sym_name); - strncpy (qualified_name, dll_name, dll_name_len); - qualified_name[dll_name_len] = '!'; - strcpy (qualified_name + dll_name_len + 1, sym_name); + qualified_name = xstrprintf ("%s!%s", dll_name, bare_name); - prim_record_minimal_symbol (qualified_name, - vma, section_data->ms_type, objfile); + if ((section_data->ms_type == mst_unknown) && debug_coff_pe_read) + fprintf_unfiltered (gdb_stdlog , _("Unknown section type for \"%s\"" + " for entry \"%s\" in dll \"%s\"\n"), + section_data->section_name, sym_name, dll_name); + prim_record_minimal_symbol (qualified_name, vma, + section_data->ms_type, objfile); + + /* Enter the plain name as well, which might not be unique. */ + prim_record_minimal_symbol (bare_name, vma, section_data->ms_type, objfile); + if (debug_coff_pe_read > 1) + fprintf_unfiltered (gdb_stdlog, _("Adding exported symbol \"%s\"" + " in dll \"%s\"\n"), sym_name, dll_name); xfree (qualified_name); + xfree (bare_name); +} + +/* Create a minimal symbol entry for an exported forward symbol. + Return 1 if the forwarded function was found 0 otherwise. + SYM_NAME contains the exported name or NULL if exported by ordinal, + FORWARD_DLL_NAME is the name of the DLL in which the target symobl resides, + FORWARD_FUNC_NAME is the name of the target symbol in that DLL, + ORDINAL is the ordinal index value of the symbol, + DLL_NAME is the internal name of the DLL file, + OBJFILE is the objfile struct of DLL_NAME. */ + +static int +add_pe_forwarded_sym (const char *sym_name, const char *forward_dll_name, + const char *forward_func_name, int ordinal, + const char *dll_name, struct objfile *objfile) +{ + CORE_ADDR vma; + struct objfile *forward_objfile; + struct minimal_symbol *msymbol; + short section; + enum minimal_symbol_type msymtype; + int dll_name_len = strlen (dll_name); + char *qualified_name, *bare_name; + int forward_dll_name_len = strlen (forward_dll_name); + int forward_func_name_len = strlen (forward_func_name); + int forward_len = forward_dll_name_len + forward_func_name_len + 2; + char *forward_qualified_name = alloca (forward_len); + + xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name, + forward_func_name); + + + msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name, + &forward_objfile); + + if (!msymbol) + { + int i; + + for (i = 0; i < forward_dll_name_len; i++) + forward_qualified_name[i] = tolower (forward_qualified_name[i]); + msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name, + &forward_objfile); + } + + if (!msymbol) + { + if (debug_coff_pe_read) + fprintf_unfiltered (gdb_stdlog, _("Unable to find function \"%s\" in" + " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"), + forward_func_name, forward_dll_name, sym_name, + dll_name); + return 0; + } + + if (debug_coff_pe_read > 1) + fprintf_unfiltered (gdb_stdlog, _("Adding forwarded exported symbol" + " \"%s\" in dll \"%s\", pointing to \"%s\"\n"), + sym_name, dll_name, forward_qualified_name); + + vma = SYMBOL_VALUE_ADDRESS (msymbol); + section = SYMBOL_SECTION (msymbol); + msymtype = MSYMBOL_TYPE (msymbol); + + /* Generate a (hopefully unique) qualified name using the first part + of the dll name, e.g. KERNEL32!AddAtomA. This matches the style + used by windbg from the "Microsoft Debugging Tools for Windows". */ + + if (sym_name == NULL || *sym_name == '\0') + bare_name = xstrprintf ("#%d", ordinal); + else + bare_name = xstrdup (sym_name); + + qualified_name = xstrprintf ("%s!%s", dll_name, bare_name); + + prim_record_minimal_symbol (qualified_name, vma, msymtype, objfile); /* Enter the plain name as well, which might not be unique. */ - prim_record_minimal_symbol (sym_name, vma, - section_data->ms_type, objfile); + prim_record_minimal_symbol (bare_name, vma, msymtype, objfile); + xfree (qualified_name); + xfree (bare_name); + + return 1; } -/* Truncate a dll_name at the first dot character. */ +/* Truncate a dll_name at the last dot character. */ static void read_pe_truncate_name (char *dll_name) { - while (*dll_name) - { - if ((*dll_name) == '.') - { - *dll_name = '\0'; /* truncates and causes loop exit. */ - } + char *last_point = strrchr (dll_name, '.'); - else - { - ++dll_name; - } - } + if (last_point != NULL) + *last_point = '\0'; } /* Low-level support functions, direct from the ld module pe-dll.c. */ @@ -169,6 +303,14 @@ pe_get32 (bfd *abfd, int where) return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); } +static unsigned int +pe_as16 (void *ptr) +{ + unsigned char *b = ptr; + + return b[0] + (b[1] << 8); +} + static unsigned int pe_as32 (void *ptr) { @@ -185,40 +327,59 @@ void read_pe_exported_syms (struct objfile *objfile) { bfd *dll = objfile->obfd; + unsigned long nbnormal, nbforward; unsigned long pe_header_offset, opthdr_ofs, num_entries, i; + unsigned long export_opthdrrva, export_opthdrsize; unsigned long export_rva, export_size, nsections, secptr, expptr; unsigned long exp_funcbase; unsigned char *expdata, *erva; unsigned long name_rvas, ordinals, nexp, ordbase; - char *dll_name; + char *dll_name = (char *) dll->filename; + int otherix = PE_SECTION_TABLE_SIZE; + int exportix = -1; int is_pe64 = 0; int is_pe32 = 0; /* Array elements are for text, data and bss in that order - Initialization with start_rva > end_rva guarantees that + Initialization with RVA_START > RVA_END guarantees that unused sections won't be matched. */ - struct read_pe_section_data section_data[PE_SECTION_TABLE_SIZE] - = { {0, 1, 0, mst_text}, - {0, 1, 0, mst_data}, - {0, 1, 0, mst_bss} - }; + struct read_pe_section_data *section_data; + struct pe_sections_info pe_sections_info; - struct cleanup *back_to = 0; + struct cleanup *back_to = make_cleanup (null_cleanup, 0); char const *target = bfd_get_target (objfile->obfd); + section_data = xzalloc (PE_SECTION_TABLE_SIZE + * sizeof (struct read_pe_section_data)); + + make_cleanup (free_current_contents, §ion_data); + + for (i=0; i < PE_SECTION_TABLE_SIZE; i++) + { + section_data[i].vma_offset = 0; + section_data[i].rva_start = 1; + section_data[i].rva_end = 0; + }; + section_data[PE_SECTION_INDEX_TEXT].ms_type = mst_text; + section_data[PE_SECTION_INDEX_TEXT].section_name = ".text"; + section_data[PE_SECTION_INDEX_DATA].ms_type = mst_data; + section_data[PE_SECTION_INDEX_DATA].section_name = ".data"; + section_data[PE_SECTION_INDEX_BSS].ms_type = mst_bss; + section_data[PE_SECTION_INDEX_BSS].section_name = ".bss"; + is_pe64 = (strcmp (target, "pe-x86-64") == 0 || strcmp (target, "pei-x86-64") == 0); is_pe32 = (strcmp (target, "pe-i386") == 0 || strcmp (target, "pei-i386") == 0 || strcmp (target, "pe-arm-wince-little") == 0 || strcmp (target, "pei-arm-wince-little") == 0); - if (!is_pe32 && !is_pe64) { /* This is not a recognized PE format file. Abort now, because the code is untested on anything else. *FIXME* test on further architectures and loosen or remove this test. */ + do_cleanups (back_to); return; } @@ -232,23 +393,24 @@ read_pe_exported_syms (struct objfile *objfile) if (num_entries < 1) /* No exports. */ { + do_cleanups (back_to); return; } - if (is_pe64) { - export_rva = pe_get32 (dll, opthdr_ofs + 112); - export_size = pe_get32 (dll, opthdr_ofs + 116); + export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112); + export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116); } else { - export_rva = pe_get32 (dll, opthdr_ofs + 96); - export_size = pe_get32 (dll, opthdr_ofs + 100); + export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96); + export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100); } nsections = pe_get16 (dll, pe_header_offset + 4 + 2); secptr = (pe_header_offset + 4 + 20 + pe_get16 (dll, pe_header_offset + 4 + 16)); expptr = 0; + export_size = 0; /* Get the rva and size of the export section. */ for (i = 0; i < nsections; i++) @@ -260,20 +422,35 @@ read_pe_exported_syms (struct objfile *objfile) unsigned long fptr = pe_get32 (dll, secptr1 + 20); bfd_seek (dll, (file_ptr) secptr1, SEEK_SET); - bfd_bread (sname, (bfd_size_type) 8, dll); + bfd_bread (sname, (bfd_size_type) sizeof (sname), dll); - if (vaddr <= export_rva && vaddr + vsize > export_rva) + if ((strcmp (sname, ".edata") == 0) + || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize)) { - expptr = fptr + (export_rva - vaddr); - if (export_rva + export_size > vaddr + vsize) - export_size = vsize - (export_rva - vaddr); + if (strcmp (sname, ".edata") != 0) + { + if (debug_coff_pe_read) + fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll " + "\"%s\" is in section \"%s\"\n"), + dll_name, sname); + } + else if (export_opthdrrva != vaddr && debug_coff_pe_read) + fprintf_unfiltered (gdb_stdlog, _("Wrong value of export RVA" + " for dll \"%s\": 0x%lx instead of 0x%lx\n"), + dll_name, export_opthdrrva, vaddr); + expptr = fptr + (export_opthdrrva - vaddr); + exportix = i; break; } } + export_rva = export_opthdrrva; + export_size = export_opthdrsize; + if (export_size == 0) { /* Empty export table. */ + do_cleanups (back_to); return; } @@ -284,12 +461,13 @@ read_pe_exported_syms (struct objfile *objfile) unsigned long secptr1 = secptr + 40 * i; unsigned long vsize = pe_get32 (dll, secptr1 + 8); unsigned long vaddr = pe_get32 (dll, secptr1 + 12); - char sec_name[9]; + unsigned long characteristics = pe_get32 (dll, secptr1 + 36); + char sec_name[SCNNMLEN + 1]; int sectix; - sec_name[8] = '\0'; bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET); - bfd_bread (sec_name, (bfd_size_type) 8, dll); + bfd_bread (sec_name, (bfd_size_type) SCNNMLEN, dll); + sec_name[SCNNMLEN] = '\0'; sectix = read_pe_section_index (sec_name); @@ -298,10 +476,32 @@ read_pe_exported_syms (struct objfile *objfile) section_data[sectix].rva_start = vaddr; section_data[sectix].rva_end = vaddr + vsize; } + else + { + char *name; + + section_data = xrealloc (section_data, (otherix + 1) + * sizeof (struct read_pe_section_data)); + name = xstrdup (sec_name); + section_data[otherix].section_name = name; + make_cleanup (xfree, name); + section_data[otherix].rva_start = vaddr; + section_data[otherix].rva_end = vaddr + vsize; + section_data[otherix].vma_offset = 0; + if (characteristics & IMAGE_SCN_CNT_CODE) + section_data[otherix].ms_type = mst_text; + else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) + section_data[otherix].ms_type = mst_data; + else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + section_data[otherix].ms_type = mst_bss; + else + section_data[otherix].ms_type = mst_unknown; + otherix++; + } } expdata = (unsigned char *) xmalloc (export_size); - back_to = make_cleanup (xfree, expdata); + make_cleanup (xfree, expdata); bfd_seek (dll, (file_ptr) expptr, SEEK_SET); bfd_bread (expdata, (bfd_size_type) export_size, dll); @@ -316,12 +516,15 @@ read_pe_exported_syms (struct objfile *objfile) /* Use internal dll name instead of full pathname. */ dll_name = pe_as32 (expdata + 12) + erva; - bfd_map_over_sections (dll, get_section_vmas, section_data); + pe_sections_info.nb_sections = otherix; + pe_sections_info.sections = section_data; + + bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info); /* Adjust the vma_offsets in case this PE got relocated. This assumes that *all* sections share the same relocation offset as the text section. */ - for (i = 0; i < PE_SECTION_TABLE_SIZE; i++) + for (i = 0; i < otherix; i++) { section_data[i].vma_offset += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); @@ -331,31 +534,185 @@ read_pe_exported_syms (struct objfile *objfile) lower case for convenience on Windows. */ read_pe_truncate_name (dll_name); + if (debug_coff_pe_read) + fprintf_unfiltered (gdb_stdlog, _("DLL \"%s\" has %ld export entries," + " base=%ld\n"), dll_name, nexp, ordbase); + nbforward = 0; + nbnormal = 0; /* Iterate through the list of symbols. */ for (i = 0; i < nexp; i++) { /* Pointer to the names vector. */ unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4); + /* Retrieve ordinal value. */ + + unsigned long ordinal = pe_as16 (erva + ordinals + i * 2); + /* Pointer to the function address vector. */ - unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4); + /* This is relatived to ordinal value. */ + unsigned long func_rva = pe_as32 (erva + exp_funcbase + + ordinal * 4); /* Find this symbol's section in our own array. */ int sectix = 0; + int section_found = 0; - for (sectix = 0; sectix < PE_SECTION_TABLE_SIZE; ++sectix) + /* First handle forward cases. */ + if (func_rva >= export_rva && func_rva < export_rva + export_size) + { + char *forward_name = (char *) (erva + func_rva); + char *funcname = (char *) (erva + name_rva); + char *forward_dll_name = forward_name; + char *forward_func_name = forward_name; + char *sep = strrchr (forward_name, '.'); + + if (sep) + { + int len = (int) (sep - forward_name); + + forward_dll_name = alloca (len + 1); + strncpy (forward_dll_name, forward_name, len); + forward_dll_name[len] = '\0'; + forward_func_name = ++sep; + } + if (add_pe_forwarded_sym (funcname, forward_dll_name, + forward_func_name, ordinal, + dll_name, objfile) != 0) + ++nbforward; + continue; + } + + for (sectix = 0; sectix < otherix; ++sectix) { if ((func_rva >= section_data[sectix].rva_start) && (func_rva < section_data[sectix].rva_end)) { + section_found = 1; add_pe_exported_sym (erva + name_rva, - func_rva, + func_rva, ordinal, section_data + sectix, dll_name, objfile); + ++nbnormal; break; } } + if (!section_found) + { + char *funcname = (char *) (erva + name_rva); + + if (name_rva == 0) + { + add_pe_exported_sym (NULL, func_rva, ordinal, + section_data, dll_name, objfile); + ++nbnormal; + } + else if (debug_coff_pe_read) + fprintf_unfiltered (gdb_stdlog, _("Export name \"%s\" ord. %lu," + " RVA 0x%lx in dll \"%s\" not handled\n"), + funcname, ordinal, func_rva, dll_name); + } } - /* Discard expdata. */ + if (debug_coff_pe_read) + fprintf_unfiltered (gdb_stdlog, _("Finished reading \"%s\", exports %ld," + " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal, + nbforward, nbnormal + nbforward, nexp); + /* Discard expdata and section_data. */ do_cleanups (back_to); } + +/* Extract from ABFD the offset of the .text section. + This offset is mainly related to the offset within the file. + The value was previously expected to be 0x1000 for all files, + but some Windows OS core DLLs seem to use 0x10000 section alignement + which modified the return value of that function. + Still return default 0x1000 value if ABFD is NULL or + if '.text' section is not found, but that should not happen... */ + +#define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000 + +CORE_ADDR +pe_text_section_offset (struct bfd *abfd) + +{ + unsigned long pe_header_offset, opthdr_ofs, num_entries, i; + unsigned long export_rva, export_size, nsections, secptr, expptr; + unsigned long exp_funcbase; + unsigned char *expdata, *erva; + unsigned long name_rvas, ordinals, nexp, ordbase; + char *dll_name; + int is_pe64 = 0; + int is_pe32 = 0; + char const *target; + + if (!abfd) + return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET; + + target = bfd_get_target (abfd); + + is_pe64 = (strcmp (target, "pe-x86-64") == 0 + || strcmp (target, "pei-x86-64") == 0); + is_pe32 = (strcmp (target, "pe-i386") == 0 + || strcmp (target, "pei-i386") == 0 + || strcmp (target, "pe-arm-wince-little") == 0 + || strcmp (target, "pei-arm-wince-little") == 0); + + if (!is_pe32 && !is_pe64) + { + /* This is not a recognized PE format file. Abort now, because + the code is untested on anything else. *FIXME* test on + further architectures and loosen or remove this test. */ + return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET; + } + + /* Get pe_header, optional header and numbers of sections. */ + pe_header_offset = pe_get32 (abfd, 0x3c); + opthdr_ofs = pe_header_offset + 4 + 20; + nsections = pe_get16 (abfd, pe_header_offset + 4 + 2); + secptr = (pe_header_offset + 4 + 20 + + pe_get16 (abfd, pe_header_offset + 4 + 16)); + + /* Get the rva and size of the export section. */ + for (i = 0; i < nsections; i++) + { + char sname[SCNNMLEN + 1]; + unsigned long secptr1 = secptr + 40 * i; + unsigned long vaddr = pe_get32 (abfd, secptr1 + 12); + + bfd_seek (abfd, (file_ptr) secptr1, SEEK_SET); + bfd_bread (sname, (bfd_size_type) SCNNMLEN, abfd); + sname[SCNNMLEN] = '\0'; + if (strcmp (sname, ".text") == 0) + return vaddr; + } + + return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET; +} + +/* Implements "show debug coff_pe_read" command. */ + +static void +show_debug_coff_pe_read (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Coff PE read debugging is %s.\n"), value); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ + +void _initialize_coff_pe_read (void); + +/* Adds "Set/show debug coff_pe_read" commands. */ + +void +_initialize_coff_pe_read (void) +{ + add_setshow_zuinteger_cmd ("coff-pe-read", class_maintenance, + &debug_coff_pe_read, + _("Set coff PE read debugging."), + _("Show coff PE read debugging."), + _("When set, debugging messages for coff reading " + "of exported symbols are displayed."), + NULL, show_debug_coff_pe_read, + &setdebuglist, &showdebuglist); +} diff --git a/contrib/gdb-7/gdb/coff-pe-read.h b/contrib/gdb-7/gdb/coff-pe-read.h index 5dbe8781ec..2e6ebbfa74 100644 --- a/contrib/gdb-7/gdb/coff-pe-read.h +++ b/contrib/gdb-7/gdb/coff-pe-read.h @@ -1,6 +1,6 @@ /* Interface to coff-pe-read.c (portable-executable-specific symbol reader). - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -23,9 +23,14 @@ #define COFF_PE_READ_H struct objfile; +struct bfd; /* Read the export table and convert it to minimal symbol table entries */ extern void read_pe_exported_syms (struct objfile *objfile); +/* Extract from ABFD the offset of the .text section. + Returns default value 0x1000 if information is not found. */ +extern CORE_ADDR pe_text_section_offset (struct bfd *abfd); + #endif /* !defined (COFF_PE_READ_H) */ diff --git a/contrib/gdb-7/gdb/coffread.c b/contrib/gdb-7/gdb/coffread.c index c727228b8f..3cc14cefab 100644 --- a/contrib/gdb-7/gdb/coffread.c +++ b/contrib/gdb-7/gdb/coffread.c @@ -1,5 +1,5 @@ /* Read coff symbol tables and convert to internal format, for GDB. - Copyright (C) 1987-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1987-2013 Free Software Foundation, Inc. Contributed by David D. Johnson, Brown University (ddj@cs.brown.edu). This file is part of GDB. @@ -47,6 +47,10 @@ extern void _initialize_coffread (void); +/* Key for COFF-associated data. */ + +static const struct objfile_data *coff_objfile_data_key; + /* The objfile we are currently reading. */ static struct objfile *coffread_objfile; @@ -311,7 +315,7 @@ cs_section_address (struct coff_symbol *cs, bfd *abfd) args.resultp = § bfd_map_over_sections (abfd, find_targ_sec, &args); if (sect != NULL) - addr = bfd_get_section_vma (objfile->obfd, sect); + addr = bfd_get_section_vma (abfd, sect); return addr; } @@ -392,9 +396,7 @@ coff_start_symtab (const char *name) static void complete_symtab (const char *name, CORE_ADDR start_addr, unsigned int size) { - if (last_source_file != NULL) - xfree (last_source_file); - last_source_file = xstrdup (name); + set_last_source_file (name); current_source_start_addr = start_addr; current_source_end_addr = start_addr + size; } @@ -413,7 +415,7 @@ coff_end_symtab (struct objfile *objfile) SECT_OFF_TEXT (objfile)); /* Reinitialize for beginning of new file. */ - last_source_file = NULL; + set_last_source_file (NULL); } static struct minimal_symbol * @@ -450,26 +452,21 @@ record_minimal_symbol (struct coff_symbol *cs, CORE_ADDR address, static void coff_symfile_init (struct objfile *objfile) { - /* Allocate struct to keep track of stab reading. */ - objfile->deprecated_sym_stab_info = (struct dbx_symfile_info *) - xmalloc (sizeof (struct dbx_symfile_info)); + struct dbx_symfile_info *dbx; + struct coff_symfile_info *coff; - memset (objfile->deprecated_sym_stab_info, 0, - sizeof (struct dbx_symfile_info)); + /* Allocate struct to keep track of stab reading. */ + dbx = XCNEW (struct dbx_symfile_info); + set_objfile_data (objfile, dbx_objfile_data_key, dbx); /* Allocate struct to keep track of the symfile. */ - objfile->deprecated_sym_private - = xmalloc (sizeof (struct coff_symfile_info)); - - memset (objfile->deprecated_sym_private, 0, - sizeof (struct coff_symfile_info)); + coff = XCNEW (struct coff_symfile_info); + set_objfile_data (objfile, coff_objfile_data_key, coff); /* COFF objects may be reordered, so set OBJF_REORDERED. If we find this causes a significant slowdown in gdb then we could set it in the debug symbol readers only when necessary. */ objfile->flags |= OBJF_REORDERED; - - init_entry_point_info (objfile); } /* This function is called for every section; it finds the outer @@ -527,8 +524,8 @@ coff_symfile_read (struct objfile *objfile, int symfile_flags) struct cleanup *back_to, *cleanup_minimal_symbols; int stabstrsize; - info = (struct coff_symfile_info *) objfile->deprecated_sym_private; - dbxinfo = objfile->deprecated_sym_stab_info; + info = objfile_data (objfile, coff_objfile_data_key); + dbxinfo = DBX_SYMFILE_INFO (objfile); symfile_bfd = abfd; /* Kludge for swap routines. */ /* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ @@ -653,13 +650,14 @@ coff_symfile_read (struct objfile *objfile, int symfile_flags) char *debugfile; debugfile = find_separate_debug_file_by_debuglink (objfile); + make_cleanup (xfree, debugfile); if (debugfile) { bfd *abfd = symfile_bfd_open (debugfile); + make_cleanup_bfd_unref (abfd); symbol_file_add_separate (abfd, symfile_flags, objfile); - xfree (debugfile); } } @@ -680,11 +678,6 @@ coff_new_init (struct objfile *ignore) static void coff_symfile_finish (struct objfile *objfile) { - if (objfile->deprecated_sym_private != NULL) - { - xfree (objfile->deprecated_sym_private); - } - /* Let stabs reader clean up. */ stabsread_clear_cache (); @@ -750,7 +743,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms, coffread_objfile = objfile; nlist_bfd_global = objfile->obfd; nlist_nsyms_global = nsyms; - last_source_file = NULL; + set_last_source_file (NULL); memset (opaque_type_chain, 0, sizeof opaque_type_chain); if (type_vector) /* Get rid of previous one. */ @@ -771,7 +764,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms, if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE) { - if (last_source_file) + if (get_last_source_file ()) coff_end_symtab (objfile); coff_start_symtab ("_globals_"); @@ -787,7 +780,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms, /* Special case for file with type declarations only, no text. */ - if (!last_source_file && SDB_TYPE (cs->c_type) + if (!get_last_source_file () && SDB_TYPE (cs->c_type) && cs->c_secnum == N_DEBUG) complete_symtab (filestring, 0, 0); @@ -836,7 +829,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms, /* Complete symbol table for last object file containing debugging information. */ - if (last_source_file) + if (get_last_source_file ()) { coff_end_symtab (objfile); coff_start_symtab (filestring); @@ -940,7 +933,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms, cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXTFUNC || cs->c_sclass == C_THUMBEXT ? mst_text : mst_file_text; - tmpaddr = gdbarch_smash_text_address (gdbarch, tmpaddr); + tmpaddr = gdbarch_addr_bits_remove (gdbarch, tmpaddr); } else if (bfd_section->flags & SEC_ALLOC && bfd_section->flags & SEC_LOAD) @@ -1126,7 +1119,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms, read_pe_exported_syms (objfile); } - if (last_source_file) + if (get_last_source_file ()) coff_end_symtab (objfile); /* Patch up any opaque types (references to types that are not defined @@ -1306,7 +1299,6 @@ static const char * coff_getfilename (union internal_auxent *aux_entry) { static char buffer[BUFSIZ]; - char *temp; const char *result; if (aux_entry->x_file.x_n.x_zeroes == 0) @@ -1455,10 +1447,11 @@ patch_type (struct type *type, struct type *real_type) if (TYPE_NAME (real_target)) { + /* The previous copy of TYPE_NAME is allocated by + process_coff_symbol. */ if (TYPE_NAME (target)) - xfree (TYPE_NAME (target)); - TYPE_NAME (target) = concat (TYPE_NAME (real_target), - (char *) NULL); + xfree ((char*) TYPE_NAME (target)); + TYPE_NAME (target) = xstrdup (TYPE_NAME (real_target)); } } @@ -1470,7 +1463,7 @@ static void patch_opaque_types (struct symtab *s) { struct block *b; - struct dict_iterator iter; + struct block_iterator iter; struct symbol *real_sym; /* Go through the per-file symbols only. */ @@ -1486,7 +1479,7 @@ patch_opaque_types (struct symtab *s) && TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR && TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0) { - char *name = SYMBOL_LINKAGE_NAME (real_sym); + const char *name = SYMBOL_LINKAGE_NAME (real_sym); int hash = hashname (name); struct symbol *sym, *prev; @@ -1675,7 +1668,7 @@ process_coff_symbol (struct coff_symbol *cs, } else TYPE_NAME (SYMBOL_TYPE (sym)) = - concat (SYMBOL_LINKAGE_NAME (sym), (char *) NULL); + xstrdup (SYMBOL_LINKAGE_NAME (sym)); } /* Keep track of any type which points to empty structured @@ -2018,8 +2011,8 @@ coff_read_struct_type (int index, int length, int lastsym, list = new; /* Save the data. */ - list->field.name = obsavestring (name, strlen (name), - &objfile->objfile_obstack); + list->field.name = obstack_copy0 (&objfile->objfile_obstack, + name, strlen (name)); FIELD_TYPE (list->field) = decode_type (ms, ms->c_type, &sub_aux, objfile); SET_FIELD_BITPOS (list->field, 8 * ms->c_value); @@ -2035,8 +2028,8 @@ coff_read_struct_type (int index, int length, int lastsym, list = new; /* Save the data. */ - list->field.name = obsavestring (name, strlen (name), - &objfile->objfile_obstack); + list->field.name = obstack_copy0 (&objfile->objfile_obstack, + name, strlen (name)); FIELD_TYPE (list->field) = decode_type (ms, ms->c_type, &sub_aux, objfile); SET_FIELD_BITPOS (list->field, ms->c_value); @@ -2109,8 +2102,8 @@ coff_read_enum_type (int index, int length, int lastsym, memset (sym, 0, sizeof (struct symbol)); SYMBOL_SET_LINKAGE_NAME (sym, - obsavestring (name, strlen (name), - &objfile->objfile_obstack)); + obstack_copy0 (&objfile->objfile_obstack, + name, strlen (name))); SYMBOL_CLASS (sym) = LOC_CONST; SYMBOL_DOMAIN (sym) = VAR_DOMAIN; SYMBOL_VALUE (sym) = ms->c_value; @@ -2158,7 +2151,7 @@ coff_read_enum_type (int index, int length, int lastsym, SYMBOL_TYPE (xsym) = type; TYPE_FIELD_NAME (type, n) = SYMBOL_LINKAGE_NAME (xsym); - SET_FIELD_BITPOS (TYPE_FIELD (type, n), SYMBOL_VALUE (xsym)); + SET_FIELD_ENUMVAL (TYPE_FIELD (type, n), SYMBOL_VALUE (xsym)); if (SYMBOL_VALUE (xsym) < 0) unsigned_enum = 0; TYPE_FIELD_BITSIZE (type, n) = 0; @@ -2195,11 +2188,23 @@ static const struct sym_fns coff_sym_fns = default_symfile_relocate, /* sym_relocate: Relocate a debug section. */ + NULL, /* sym_probe_fns */ &psym_functions }; +/* Free the per-objfile COFF data. */ + +static void +coff_free_info (struct objfile *objfile, void *arg) +{ + xfree (arg); +} + void _initialize_coffread (void) { add_symtab_fns (&coff_sym_fns); + + coff_objfile_data_key = register_objfile_data_with_cleanup (NULL, + coff_free_info); } diff --git a/contrib/gdb-7/gdb/command.h b/contrib/gdb-7/gdb/command.h index d32e98e515..a25fe04090 100644 --- a/contrib/gdb-7/gdb/command.h +++ b/contrib/gdb-7/gdb/command.h @@ -1,7 +1,6 @@ -/* Header file for command-reading library command.c. +/* Header file for command creation. - Copyright (C) 1986, 1989-1995, 1999-2000, 2002, 2004, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 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 @@ -19,6 +18,11 @@ #if !defined (COMMAND_H) #define COMMAND_H 1 +#include "gdb_vecs.h" + +/* This file defines the public interface for any code wanting to + create commands. */ + /* Command classes are top-level categories into which commands are broken down for "help" purposes. @@ -72,7 +76,8 @@ typedef enum var_types /* Like var_uinteger but signed. *VAR is an int. The user can type 0 to mean "unlimited", which is stored in *VAR as - INT_MAX. */ + INT_MAX. The only remaining use of it is the Python API. + Don't use it elsewhere. */ var_integer, /* String which the user enters with escapes (e.g. the user types @@ -88,12 +93,16 @@ typedef enum var_types /* String which stores a filename. (*VAR) is a malloc'd string. */ var_filename, - /* ZeroableInteger. *VAR is an int. Like Unsigned Integer except + /* ZeroableInteger. *VAR is an int. Like var_integer except that zero really means zero. */ var_zinteger, /* ZeroableUnsignedInteger. *VAR is an unsigned int. Zero really means zero. */ var_zuinteger, + /* ZeroableUnsignedInteger with unlimited value. *VAR is an int, + but its range is [0, INT_MAX]. -1 stands for unlimited and + other negative numbers are not allowed. */ + var_zuinteger_unlimited, /* Enumerated type. Can only have one of the specified values. *VAR is a char pointer to the name of the element that we find. */ @@ -106,6 +115,8 @@ struct cmd_list_element; /* Forward-declarations of the entry-points of cli/cli-decode.c. */ +/* API to the manipulation of command lists. */ + extern int valid_user_defined_cmd_name_p (const char *name); extern struct cmd_list_element *add_cmd (char *, enum command_class, @@ -144,9 +155,10 @@ typedef void cmd_sfunc_ftype (char *args, int from_tty, extern void set_cmd_sfunc (struct cmd_list_element *cmd, cmd_sfunc_ftype *sfunc); -extern void set_cmd_completer (struct cmd_list_element *, - char **(*completer) (struct cmd_list_element *, - char *, char *)); +typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *, + char *, char *); + +extern void set_cmd_completer (struct cmd_list_element *, completer_ftype *); /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs around in cmd objects to test the value of the commands sfunc(). */ @@ -168,6 +180,8 @@ extern void execute_cmd_post_hook (struct cmd_list_element *cmd); /* Return the type of the command. */ extern enum cmd_types cmd_type (struct cmd_list_element *cmd); +/* Flag for an ambiguous cmd_list result. */ +#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1) extern struct cmd_list_element *lookup_cmd (char **, struct cmd_list_element *, char *, @@ -201,21 +215,17 @@ extern struct cmd_list_element *add_info (char *, extern struct cmd_list_element *add_info_alias (char *, char *, int); -extern char **complete_on_cmdlist (struct cmd_list_element *, - char *, char *); +extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *, + char *, char *, int); -extern char **complete_on_enum (const char *enumlist[], - char *, char *); +extern VEC (char_ptr) *complete_on_enum (const char *const *enumlist, + char *, char *); -extern void help_cmd (char *, struct ui_file *); +/* Functions that implement commands about CLI commands. */ extern void help_list (struct cmd_list_element *, char *, enum command_class, struct ui_file *); -extern void help_cmd_list (struct cmd_list_element *, - enum command_class, - char *, int, struct ui_file *); - /* Method for show a set/show variable's VALUE on FILE. If this method isn't supplied deprecated_show_value_hack() is called (which is not good). */ @@ -229,7 +239,7 @@ extern show_value_ftype deprecated_show_value_hack; extern void add_setshow_enum_cmd (char *name, enum command_class class, - const char *enumlist[], + const char *const *enumlist, const char **var, const char *set_doc, const char *show_doc, @@ -282,16 +292,17 @@ extern void add_setshow_string_cmd (char *name, struct cmd_list_element **set_list, struct cmd_list_element **show_list); -extern void add_setshow_string_noescape_cmd (char *name, - enum command_class class, - char **var, - const char *set_doc, - const char *show_doc, - const char *help_doc, - cmd_sfunc_ftype *set_func, - show_value_ftype *show_func, - struct cmd_list_element **set_list, - struct cmd_list_element **show_list); +extern struct cmd_list_element *add_setshow_string_noescape_cmd + (char *name, + enum command_class class, + char **var, + const char *set_doc, + const char *show_doc, + const char *help_doc, + cmd_sfunc_ftype *set_func, + show_value_ftype *show_func, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list); extern void add_setshow_optional_filename_cmd (char *name, enum command_class class, @@ -348,6 +359,18 @@ extern void add_setshow_zuinteger_cmd (char *name, struct cmd_list_element **set_list, struct cmd_list_element **show_list); +extern void + add_setshow_zuinteger_unlimited_cmd (char *name, + enum command_class class, + int *var, + const char *set_doc, + const char *show_doc, + const char *help_doc, + cmd_sfunc_ftype *set_func, + show_value_ftype *show_func, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list); + /* Do a "show" command for each thing on a command list. */ extern void cmd_show_list (struct cmd_list_element *, int, char *); diff --git a/contrib/gdb-7/gdb/common/agent.c b/contrib/gdb-7/gdb/common/agent.c new file mode 100644 index 0000000000..632310d72f --- /dev/null +++ b/contrib/gdb-7/gdb/common/agent.c @@ -0,0 +1,356 @@ +/* Shared utility routines for GDB to interact with agent. + + Copyright (C) 2009-2013 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 . */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#include "target.h" +#include "inferior.h" /* for non_stop */ +#endif + +#include +#include +#include "agent.h" + +int debug_agent = 0; + +#ifdef GDBSERVER +#define DEBUG_AGENT(fmt, args...) \ + if (debug_agent) \ + fprintf (stderr, fmt, ##args); +#else +#define DEBUG_AGENT(fmt, args...) \ + if (debug_agent) \ + fprintf_unfiltered (gdb_stdlog, fmt, ##args); +#endif + +/* Global flag to determine using agent or not. */ +int use_agent = 0; + +/* Addresses of in-process agent's symbols both GDB and GDBserver cares + about. */ + +struct ipa_sym_addresses +{ + CORE_ADDR addr_helper_thread_id; + CORE_ADDR addr_cmd_buf; + CORE_ADDR addr_capability; +}; + +/* Cache of the helper thread id. FIXME: this global should be made + per-process. */ +static unsigned int helper_thread_id = 0; + +static struct +{ + const char *name; + int offset; + int required; +} symbol_list[] = { + IPA_SYM(helper_thread_id), + IPA_SYM(cmd_buf), + IPA_SYM(capability), +}; + +static struct ipa_sym_addresses ipa_sym_addrs; + +static int all_agent_symbols_looked_up = 0; + +int +agent_loaded_p (void) +{ + return all_agent_symbols_looked_up; +} + +/* Look up all symbols needed by agent. Return 0 if all the symbols are + found, return non-zero otherwise. */ + +int +agent_look_up_symbols (void *arg) +{ + int i; + + all_agent_symbols_looked_up = 0; + + for (i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++) + { + CORE_ADDR *addrp = + (CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset); +#ifdef GDBSERVER + + if (look_up_one_symbol (symbol_list[i].name, addrp, 1) == 0) +#else + struct minimal_symbol *sym = + lookup_minimal_symbol (symbol_list[i].name, NULL, + (struct objfile *) arg); + + if (sym != NULL) + *addrp = SYMBOL_VALUE_ADDRESS (sym); + else +#endif + { + DEBUG_AGENT ("symbol `%s' not found\n", symbol_list[i].name); + return -1; + } + } + + all_agent_symbols_looked_up = 1; + return 0; +} + +static unsigned int +agent_get_helper_thread_id (void) +{ + if (helper_thread_id == 0) + { +#ifdef GDBSERVER + if (read_inferior_memory (ipa_sym_addrs.addr_helper_thread_id, + (unsigned char *) &helper_thread_id, + sizeof helper_thread_id)) +#else + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); + gdb_byte buf[4]; + + if (target_read_memory (ipa_sym_addrs.addr_helper_thread_id, + buf, sizeof buf) == 0) + helper_thread_id = extract_unsigned_integer (buf, sizeof buf, + byte_order); + else +#endif + { + warning (_("Error reading helper thread's id in lib")); + } + } + + return helper_thread_id; +} + +#ifdef HAVE_SYS_UN_H +#include +#include +#define SOCK_DIR P_tmpdir + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path) +#endif + +#endif + +/* Connects to synchronization socket. PID is the pid of inferior, which is + used to set up the connection socket. */ + +static int +gdb_connect_sync_socket (int pid) +{ +#ifdef HAVE_SYS_UN_H + struct sockaddr_un addr; + int res, fd; + char path[UNIX_PATH_MAX]; + + res = xsnprintf (path, UNIX_PATH_MAX, "%s/gdb_ust%d", P_tmpdir, pid); + if (res >= UNIX_PATH_MAX) + return -1; + + res = fd = socket (PF_UNIX, SOCK_STREAM, 0); + if (res == -1) + { + warning (_("error opening sync socket: %s"), strerror (errno)); + return -1; + } + + addr.sun_family = AF_UNIX; + + res = xsnprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path); + if (res >= UNIX_PATH_MAX) + { + warning (_("string overflow allocating socket name")); + close (fd); + return -1; + } + + res = connect (fd, (struct sockaddr *) &addr, sizeof (addr)); + if (res == -1) + { + warning (_("error connecting sync socket (%s): %s. " + "Make sure the directory exists and that it is writable."), + path, strerror (errno)); + close (fd); + return -1; + } + + return fd; +#else + return -1; +#endif +} + +/* Execute an agent command in the inferior. PID is the value of pid of the + inferior. CMD is the buffer for command. GDB or GDBserver will store the + command into it and fetch the return result from CMD. The interaction + between GDB/GDBserver and the agent is synchronized by a synchronization + socket. Return zero if success, otherwise return non-zero. */ + +int +agent_run_command (int pid, const char *cmd, int len) +{ + int fd; + int tid = agent_get_helper_thread_id (); + ptid_t ptid = ptid_build (pid, tid, 0); + +#ifdef GDBSERVER + int ret = write_inferior_memory (ipa_sym_addrs.addr_cmd_buf, + (const unsigned char *) cmd, len); +#else + int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf, cmd, len); +#endif + + if (ret != 0) + { + warning (_("unable to write")); + return -1; + } + + DEBUG_AGENT ("agent: resumed helper thread\n"); + + /* Resume helper thread. */ +#ifdef GDBSERVER +{ + struct thread_resume resume_info; + + resume_info.thread = ptid; + resume_info.kind = resume_continue; + resume_info.sig = GDB_SIGNAL_0; + (*the_target->resume) (&resume_info, 1); +} +#else + target_resume (ptid, 0, GDB_SIGNAL_0); +#endif + + fd = gdb_connect_sync_socket (pid); + if (fd >= 0) + { + char buf[1] = ""; + int ret; + + DEBUG_AGENT ("agent: signalling helper thread\n"); + + do + { + ret = write (fd, buf, 1); + } while (ret == -1 && errno == EINTR); + + DEBUG_AGENT ("agent: waiting for helper thread's response\n"); + + do + { + ret = read (fd, buf, 1); + } while (ret == -1 && errno == EINTR); + + close (fd); + + DEBUG_AGENT ("agent: helper thread's response received\n"); + } + else + return -1; + + /* Need to read response with the inferior stopped. */ + if (!ptid_equal (ptid, null_ptid)) + { + struct target_waitstatus status; + int was_non_stop = non_stop; + /* Stop thread PTID. */ + DEBUG_AGENT ("agent: stop helper thread\n"); +#ifdef GDBSERVER + { + struct thread_resume resume_info; + + resume_info.thread = ptid; + resume_info.kind = resume_stop; + resume_info.sig = GDB_SIGNAL_0; + (*the_target->resume) (&resume_info, 1); + } + + non_stop = 1; + mywait (ptid, &status, 0, 0); +#else + non_stop = 1; + target_stop (ptid); + + memset (&status, 0, sizeof (status)); + target_wait (ptid, &status, 0); +#endif + non_stop = was_non_stop; + } + + if (fd >= 0) + { +#ifdef GDBSERVER + if (read_inferior_memory (ipa_sym_addrs.addr_cmd_buf, + (unsigned char *) cmd, IPA_CMD_BUF_SIZE)) +#else + if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd, + IPA_CMD_BUF_SIZE)) +#endif + { + warning (_("Error reading command response")); + return -1; + } + } + + return 0; +} + +/* Each bit of it stands for a capability of agent. */ +static unsigned int agent_capability = 0; + +/* Return true if agent has capability AGENT_CAP, otherwise return false. */ + +int +agent_capability_check (enum agent_capa agent_capa) +{ + if (agent_capability == 0) + { +#ifdef GDBSERVER + if (read_inferior_memory (ipa_sym_addrs.addr_capability, + (unsigned char *) &agent_capability, + sizeof agent_capability)) +#else + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); + gdb_byte buf[4]; + + if (target_read_memory (ipa_sym_addrs.addr_capability, + buf, sizeof buf) == 0) + agent_capability = extract_unsigned_integer (buf, sizeof buf, + byte_order); + else +#endif + warning (_("Error reading capability of agent")); + } + return agent_capability & agent_capa; +} + +/* Invalidate the cache of agent capability, so we'll read it from inferior + again. Call it when launches a new program or reconnect to remote stub. */ + +void +agent_capability_invalidate (void) +{ + agent_capability = 0; +} diff --git a/contrib/gdb-7/gdb/common/agent.h b/contrib/gdb-7/gdb/common/agent.h new file mode 100644 index 0000000000..a75f8904c5 --- /dev/null +++ b/contrib/gdb-7/gdb/common/agent.h @@ -0,0 +1,57 @@ +/* Shared utility routines for GDB to interact with agent. + + Copyright (C) 2009-2013 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 agent_run_command (int pid, const char *cmd, int len); + +int agent_look_up_symbols (void *); + +#define STRINGIZE_1(STR) #STR +#define STRINGIZE(STR) STRINGIZE_1(STR) +#define IPA_SYM(SYM) \ + { \ + STRINGIZE (gdb_agent_ ## SYM), \ + offsetof (struct ipa_sym_addresses, addr_ ## SYM) \ + } + +/* The size in bytes of the buffer used to talk to the IPA helper + thread. */ +#define IPA_CMD_BUF_SIZE 1024 + +int agent_loaded_p (void); + +extern int debug_agent; + +extern int use_agent; + +/* Capability of agent. Different agents may have different capabilities, + such as installing fast tracepoint or evaluating breakpoint conditions. + Capabilities are represented by bit-maps, and each capability occupies one + bit. */ + +enum agent_capa +{ + /* Capability to install fast tracepoint. */ + AGENT_CAPA_FAST_TRACE = 0x1, + /* Capability to install static tracepoint. */ + AGENT_CAPA_STATIC_TRACE = (0x1 << 1), +}; + +int agent_capability_check (enum agent_capa); + +void agent_capability_invalidate (void); diff --git a/contrib/gdb-7/gdb/common/ax.def b/contrib/gdb-7/gdb/common/ax.def index fdc043fdb4..06ae70baca 100644 --- a/contrib/gdb-7/gdb/common/ax.def +++ b/contrib/gdb-7/gdb/common/ax.def @@ -1,5 +1,5 @@ /* Definition of agent opcode values. -*- c -*- - Copyright (C) 1998-2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1998-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -93,3 +93,5 @@ DEFOP (invalid2, 0, 0, 0, 0, 0x31) express the right thing. */ DEFOP (pick, 1, 0, 0, 1, 0x32) DEFOP (rot, 0, 0, 3, 3, 0x33) +/* Both the argument and consumed numbers are dynamic for this one. */ +DEFOP (printf, 0, 0, 0, 0, 0x34) diff --git a/contrib/gdb-7/gdb/common/btrace-common.h b/contrib/gdb-7/gdb/common/btrace-common.h new file mode 100644 index 0000000000..b157c7c000 --- /dev/null +++ b/contrib/gdb-7/gdb/common/btrace-common.h @@ -0,0 +1,73 @@ +/* Branch trace support for GDB, the GNU debugger. + + Copyright (C) 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. . + + 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 BTRACE_COMMON_H +#define BTRACE_COMMON_H + +/* Branch tracing (btrace) is a per-thread control-flow execution trace of the + inferior. For presentation purposes, the branch trace is represented as a + list of sequential control-flow blocks, one such list per thread. */ + +#ifdef GDBSERVER +# include "server.h" +#else +# include "defs.h" +#endif + +#include "vec.h" + +/* A branch trace block. + + This represents a block of sequential control-flow. Adjacent blocks will be + connected via calls, returns, or jumps. The latter can be direct or + indirect, conditional or unconditional. Branches can further be + asynchronous, e.g. interrupts. */ +struct btrace_block +{ + /* The address of the first byte of the first instruction in the block. */ + CORE_ADDR begin; + + /* The address of the first byte of the last instruction in the block. */ + CORE_ADDR end; +}; + +/* Branch trace is represented as a vector of branch trace blocks starting with + the most recent block. */ +typedef struct btrace_block btrace_block_s; + +/* Define functions operating on a vector of branch trace blocks. */ +DEF_VEC_O (btrace_block_s); + +/* Target specific branch trace information. */ +struct btrace_target_info; + +/* Enumeration of btrace read types. */ + +enum btrace_read_type +{ + /* Send all available trace. */ + btrace_read_all, + + /* Send all available trace, if it changed. */ + btrace_read_new +}; + +#endif /* BTRACE_COMMON_H */ diff --git a/contrib/gdb-7/gdb/common/buffer.c b/contrib/gdb-7/gdb/common/buffer.c index 37b7b55f74..ee5d35e8f6 100644 --- a/contrib/gdb-7/gdb/common/buffer.c +++ b/contrib/gdb-7/gdb/common/buffer.c @@ -1,6 +1,6 @@ /* A simple growing buffer for GDB. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -25,10 +25,12 @@ #include "xml-utils.h" #include "buffer.h" +#include "inttypes.h" #include #include #include +#include void buffer_grow (struct buffer *buffer, const char *data, size_t size) @@ -47,8 +49,6 @@ buffer_grow (struct buffer *buffer, const char *data, size_t size) while (buffer->used_size + size > new_buffer_size) new_buffer_size *= 2; new_buffer = xrealloc (buffer->buffer, new_buffer_size); - if (!new_buffer) - abort (); memcpy (new_buffer + buffer->used_size, data, size); buffer->buffer = new_buffer; buffer->buffer_size = new_buffer_size; @@ -101,6 +101,7 @@ buffer_xml_printf (struct buffer *buffer, const char *format, ...) char buf[32]; char *p; char *str = buf; + const char *f_old = f; switch (*f) { @@ -119,14 +120,60 @@ buffer_xml_printf (struct buffer *buffer, const char *format, ...) case 'o': sprintf (str, "%o", va_arg (ap, unsigned int)); break; + case 'l': + f++; + switch (*f) + { + case 'd': + sprintf (str, "%ld", va_arg (ap, long)); + break; + case 'u': + sprintf (str, "%lu", va_arg (ap, unsigned long)); + break; + case 'x': + sprintf (str, "%lx", va_arg (ap, unsigned long)); + break; + case 'o': + sprintf (str, "%lo", va_arg (ap, unsigned long)); + break; + case 'l': + f++; + switch (*f) + { + case 'd': + sprintf (str, "%" PRId64, + (int64_t) va_arg (ap, long long)); + break; + case 'u': + sprintf (str, "%" PRIu64, + (uint64_t) va_arg (ap, unsigned long long)); + break; + case 'x': + sprintf (str, "%" PRIx64, + (uint64_t) va_arg (ap, unsigned long long)); + break; + case 'o': + sprintf (str, "%" PRIo64, + (uint64_t) va_arg (ap, unsigned long long)); + break; + default: + str = 0; + break; + } + break; + default: + str = 0; + break; + } + break; default: str = 0; break; } - + if (str) { - buffer_grow (buffer, prev, f - prev - 1); + buffer_grow (buffer, prev, f_old - prev - 1); p = xml_escape_text (str); buffer_grow_str (buffer, p); xfree (p); diff --git a/contrib/gdb-7/gdb/common/buffer.h b/contrib/gdb-7/gdb/common/buffer.h index e4bad09238..568543abd7 100644 --- a/contrib/gdb-7/gdb/common/buffer.h +++ b/contrib/gdb-7/gdb/common/buffer.h @@ -1,6 +1,6 @@ /* A simple growing buffer for GDB. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/common-utils.c b/contrib/gdb-7/gdb/common/common-utils.c index ad01ed658d..4204abf821 100644 --- a/contrib/gdb-7/gdb/common/common-utils.c +++ b/contrib/gdb-7/gdb/common/common-utils.c @@ -1,6 +1,6 @@ /* Shared general utility routines for GDB, the GNU debugger. - Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -24,6 +24,7 @@ #endif #include "gdb_assert.h" +#include "gdb_string.h" #include #include @@ -137,22 +138,6 @@ xstrvprintf (const char *format, va_list ap) return ret; } -void -xasprintf (char **ret, const char *format, ...) -{ - va_list args; - - va_start (args, format); - (*ret) = xstrvprintf (format, args); - va_end (args); -} - -void -xvasprintf (char **ret, const char *format, va_list ap) -{ - (*ret) = xstrvprintf (format, ap); -} - int xsnprintf (char *str, size_t size, const char *format, ...) { @@ -166,3 +151,13 @@ xsnprintf (char *str, size_t size, const char *format, ...) return ret; } + +char * +savestring (const char *ptr, size_t len) +{ + char *p = (char *) xmalloc (len + 1); + + memcpy (p, ptr, len); + p[len] = 0; + return p; +} diff --git a/contrib/gdb-7/gdb/common/common-utils.h b/contrib/gdb-7/gdb/common/common-utils.h index 030bcc5305..9b659d8dac 100644 --- a/contrib/gdb-7/gdb/common/common-utils.h +++ b/contrib/gdb-7/gdb/common/common-utils.h @@ -1,6 +1,6 @@ /* Shared general utility routines for GDB, the GNU debugger. - Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -43,15 +43,14 @@ char *xstrprintf (const char *format, ...) ATTRIBUTE_PRINTF (1, 2); char *xstrvprintf (const char *format, va_list ap) ATTRIBUTE_PRINTF (1, 0); -/* Like asprintf/vasprintf but get an internal_error if the call - fails. */ -void xasprintf (char **ret, const char *format, ...) - ATTRIBUTE_PRINTF (2, 3); -void xvasprintf (char **ret, const char *format, va_list ap) - ATTRIBUTE_PRINTF (2, 0); - /* Like snprintf, but throw an error if the output buffer is too small. */ int xsnprintf (char *str, size_t size, const char *format, ...) ATTRIBUTE_PRINTF (3, 4); +/* Make a copy of the string at PTR with LEN characters + (and add a null character at the end in the copy). + Uses malloc to get the space. Returns the address of the copy. */ + +char *savestring (const char *ptr, size_t len); + #endif diff --git a/contrib/gdb-7/gdb/common/format.c b/contrib/gdb-7/gdb/common/format.c new file mode 100644 index 0000000000..580381864e --- /dev/null +++ b/contrib/gdb-7/gdb/common/format.c @@ -0,0 +1,401 @@ +/* Parse a printf-style format string. + + Copyright (C) 1986-2013 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 . */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include + +#include "format.h" + +struct format_piece * +parse_format_string (const char **arg) +{ + const char *s; + char *f, *string; + const char *prev_start; + const char *percent_loc; + char *sub_start, *current_substring; + struct format_piece *pieces; + int next_frag; + int max_pieces; + enum argclass this_argclass; + + s = *arg; + + /* Parse the format-control string and copy it into the string STRING, + processing some kinds of escape sequence. */ + + f = string = (char *) alloca (strlen (s) + 1); + + while (*s != '"' && *s != '\0') + { + int c = *s++; + switch (c) + { + case '\0': + continue; + + case '\\': + switch (c = *s++) + { + case '\\': + *f++ = '\\'; + break; + case 'a': + *f++ = '\a'; + break; + case 'b': + *f++ = '\b'; + break; + case 'f': + *f++ = '\f'; + break; + case 'n': + *f++ = '\n'; + break; + case 'r': + *f++ = '\r'; + break; + case 't': + *f++ = '\t'; + break; + case 'v': + *f++ = '\v'; + break; + case '"': + *f++ = '"'; + break; + default: + /* ??? TODO: handle other escape sequences. */ + error (_("Unrecognized escape character \\%c in format string."), + c); + } + break; + + default: + *f++ = c; + } + } + + /* Terminate our escape-processed copy. */ + *f++ = '\0'; + + /* Whether the format string ended with double-quote or zero, we're + done with it; it's up to callers to complain about syntax. */ + *arg = s; + + /* Need extra space for the '\0's. Doubling the size is sufficient. */ + + current_substring = xmalloc (strlen (string) * 2 + 1000); + + max_pieces = strlen (string) + 2; + + pieces = (struct format_piece *) + xmalloc (max_pieces * sizeof (struct format_piece)); + + next_frag = 0; + + /* Now scan the string for %-specs and see what kinds of args they want. + argclass classifies the %-specs so we can give printf-type functions + something of the right size. */ + + f = string; + prev_start = string; + while (*f) + if (*f++ == '%') + { + int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0; + int seen_space = 0, seen_plus = 0; + int seen_big_l = 0, seen_h = 0, seen_big_h = 0; + int seen_big_d = 0, seen_double_big_d = 0; + int bad = 0; + + /* Skip over "%%", it will become part of a literal piece. */ + if (*f == '%') + { + f++; + continue; + } + + sub_start = current_substring; + + strncpy (current_substring, prev_start, f - 1 - prev_start); + current_substring += f - 1 - prev_start; + *current_substring++ = '\0'; + + pieces[next_frag].string = sub_start; + pieces[next_frag].argclass = literal_piece; + next_frag++; + + percent_loc = f - 1; + + /* Check the validity of the format specifier, and work + out what argument it expects. We only accept C89 + format strings, with the exception of long long (which + we autoconf for). */ + + /* The first part of a format specifier is a set of flag + characters. */ + while (strchr ("0-+ #", *f)) + { + if (*f == '#') + seen_hash = 1; + else if (*f == '0') + seen_zero = 1; + else if (*f == ' ') + seen_space = 1; + else if (*f == '+') + seen_plus = 1; + f++; + } + + /* The next part of a format specifier is a width. */ + while (strchr ("0123456789", *f)) + f++; + + /* The next part of a format specifier is a precision. */ + if (*f == '.') + { + seen_prec = 1; + f++; + while (strchr ("0123456789", *f)) + f++; + } + + /* The next part of a format specifier is a length modifier. */ + if (*f == 'h') + { + seen_h = 1; + f++; + } + else if (*f == 'l') + { + f++; + lcount++; + if (*f == 'l') + { + f++; + lcount++; + } + } + else if (*f == 'L') + { + seen_big_l = 1; + f++; + } + /* Decimal32 modifier. */ + else if (*f == 'H') + { + seen_big_h = 1; + f++; + } + /* Decimal64 and Decimal128 modifiers. */ + else if (*f == 'D') + { + f++; + + /* Check for a Decimal128. */ + if (*f == 'D') + { + f++; + seen_double_big_d = 1; + } + else + seen_big_d = 1; + } + + switch (*f) + { + case 'u': + if (seen_hash) + bad = 1; + /* FALLTHROUGH */ + + case 'o': + case 'x': + case 'X': + if (seen_space || seen_plus) + bad = 1; + /* FALLTHROUGH */ + + case 'd': + case 'i': + if (lcount == 0) + this_argclass = int_arg; + else if (lcount == 1) + this_argclass = long_arg; + else + this_argclass = long_long_arg; + + if (seen_big_l) + bad = 1; + break; + + case 'c': + 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; + break; + + case 'p': + this_argclass = ptr_arg; + if (lcount || seen_h || seen_big_l) + bad = 1; + if (seen_prec || seen_zero || seen_space || seen_plus) + bad = 1; + break; + + case 's': + 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; + break; + + case 'e': + case 'f': + case 'g': + case 'E': + case 'G': + if (seen_big_h || seen_big_d || seen_double_big_d) + this_argclass = decfloat_arg; + else if (seen_big_l) + this_argclass = long_double_arg; + else + this_argclass = double_arg; + + if (lcount || seen_h) + bad = 1; + break; + + case '*': + error (_("`*' not supported for precision or width in printf")); + + case 'n': + error (_("Format specifier `n' not supported in printf")); + + case '\0': + error (_("Incomplete format specifier at end of format string")); + + default: + error (_("Unrecognized format specifier '%c' in printf"), *f); + } + + if (bad) + error (_("Inappropriate modifiers to " + "format specifier '%c' in printf"), + *f); + + f++; + + sub_start = current_substring; + + if (lcount > 1 && USE_PRINTF_I64) + { + /* Windows' printf does support long long, but not the usual way. + Convert %lld to %I64d. */ + int length_before_ll = f - percent_loc - 1 - lcount; + + strncpy (current_substring, percent_loc, length_before_ll); + strcpy (current_substring + length_before_ll, "I64"); + current_substring[length_before_ll + 3] = + percent_loc[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 - percent_loc - 2; + + strncpy (current_substring, percent_loc, length_before_ls); + strcpy (current_substring + length_before_ls, "s"); + current_substring += length_before_ls + 2; + } + else + { + strncpy (current_substring, percent_loc, f - percent_loc); + current_substring += f - percent_loc; + } + + *current_substring++ = '\0'; + + prev_start = f; + + pieces[next_frag].string = sub_start; + pieces[next_frag].argclass = this_argclass; + next_frag++; + } + + /* Record the remainder of the string. */ + + sub_start = current_substring; + + strncpy (current_substring, prev_start, f - prev_start); + current_substring += f - prev_start; + *current_substring++ = '\0'; + + pieces[next_frag].string = sub_start; + pieces[next_frag].argclass = literal_piece; + next_frag++; + + /* Record an end-of-array marker. */ + + pieces[next_frag].string = NULL; + pieces[next_frag].argclass = literal_piece; + + return pieces; +} + +void +free_format_pieces (struct format_piece *pieces) +{ + if (!pieces) + return; + + /* We happen to know that all the string pieces are in the block + pointed to by the first string piece. */ + if (pieces[0].string) + xfree (pieces[0].string); + + xfree (pieces); +} + +void +free_format_pieces_cleanup (void *ptr) +{ + void **location = ptr; + + if (location == NULL) + return; + + if (*location != NULL) + { + free_format_pieces (*location); + *location = NULL; + } +} + diff --git a/contrib/gdb-7/gdb/common/format.h b/contrib/gdb-7/gdb/common/format.h new file mode 100644 index 0000000000..ba3d703cf7 --- /dev/null +++ b/contrib/gdb-7/gdb/common/format.h @@ -0,0 +1,63 @@ +/* Parse a printf-style format string. + + Copyright (C) 1986-2013 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(__MINGW32__) && !defined(PRINTF_HAS_LONG_LONG) +# define USE_PRINTF_I64 1 +# define PRINTF_HAS_LONG_LONG +#else +# define USE_PRINTF_I64 0 +#endif + +/* The argclass represents the general type of data that goes with a + format directive; int_arg for %d, long_arg for %l, and so forth. + Note that these primarily distinguish types by size and need for + special handling, so for instance %u and %x are (at present) also + classed as int_arg. */ + +enum argclass + { + literal_piece, + int_arg, long_arg, long_long_arg, ptr_arg, + string_arg, wide_string_arg, wide_char_arg, + double_arg, long_double_arg, decfloat_arg + }; + +/* A format piece is a section of the format string that may include a + single print directive somewhere in it, and the associated class + for the argument. */ + +struct format_piece +{ + char *string; + enum argclass argclass; +}; + +/* Return an array of printf fragments found at the given string, and + rewrite ARG with a pointer to the end of the format string. */ + +extern struct format_piece *parse_format_string (const char **arg); + +/* Given a pointer to an array of format pieces, free any memory that + would have been allocated by parse_format_string. */ + +extern void free_format_pieces (struct format_piece *frags); + +/* Freeing, cast as a cleanup. */ + +extern void free_format_pieces_cleanup (void *); diff --git a/contrib/gdb-7/gdb/common/gdb_assert.h b/contrib/gdb-7/gdb/common/gdb_assert.h index 351f55877e..28e8da4f74 100644 --- a/contrib/gdb-7/gdb/common/gdb_assert.h +++ b/contrib/gdb-7/gdb/common/gdb_assert.h @@ -1,5 +1,5 @@ /* GDB-friendly replacement for . - Copyright (C) 2000-2001, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,7 +22,7 @@ /* A static assertion. This will cause a compile-time error if EXPR, which must be a compile-time constant, is false. */ -#define static_assert(expr) \ +#define gdb_static_assert(expr) \ extern int never_defined_just_used_for_checking[(expr) ? 1 : -1] /* PRAGMATICS: "gdb_assert.h":gdb_assert() is a lower case (rather diff --git a/contrib/gdb-7/gdb/common/gdb_dirent.h b/contrib/gdb-7/gdb/common/gdb_dirent.h index 183dfe47e2..f86f128cd5 100644 --- a/contrib/gdb-7/gdb/common/gdb_dirent.h +++ b/contrib/gdb-7/gdb/common/gdb_dirent.h @@ -1,5 +1,5 @@ /* Portable . - Copyright (C) 2000, 2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/gdb_locale.h b/contrib/gdb-7/gdb/common/gdb_locale.h index 41e95c8efb..2f8e068e6e 100644 --- a/contrib/gdb-7/gdb/common/gdb_locale.h +++ b/contrib/gdb-7/gdb/common/gdb_locale.h @@ -1,5 +1,5 @@ /* GDB-friendly replacement for . - Copyright (C) 2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/gdb_signals.h b/contrib/gdb-7/gdb/common/gdb_signals.h index 1cc629775d..76e64f83b9 100644 --- a/contrib/gdb-7/gdb/common/gdb_signals.h +++ b/contrib/gdb-7/gdb/common/gdb_signals.h @@ -1,5 +1,5 @@ /* Target signal translation functions for GDB. - Copyright (C) 1990-2003, 2006-2012 Free Software Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. Contributed by Cygnus Support. This file is part of GDB. @@ -22,33 +22,33 @@ #include "gdb/signals.h" -/* Predicate to target_signal_to_host(). Return non-zero if the enum +/* Predicate to gdb_signal_to_host(). Return non-zero if the enum targ_signal SIGNO has an equivalent ``host'' representation. */ /* FIXME: cagney/1999-11-22: The name below was chosen in preference - to the shorter target_signal_p() because it is far less ambigious. - In this context ``target_signal'' refers to GDB's internal + to the shorter gdb_signal_p() because it is far less ambigious. + In this context ``gdb_signal'' refers to GDB's internal representation of the target's set of signals while ``host signal'' refers to the target operating system's signal. Confused? */ -extern int target_signal_to_host_p (enum target_signal signo); +extern int gdb_signal_to_host_p (enum gdb_signal signo); -/* Convert between host signal numbers and enum target_signal's. - target_signal_to_host() returns 0 and prints a warning() on GDB's +/* Convert between host signal numbers and enum gdb_signal's. + gdb_signal_to_host() returns 0 and prints a warning() on GDB's console if SIGNO has no equivalent host representation. */ /* FIXME: cagney/1999-11-22: Here ``host'' is used incorrectly, it is refering to the target operating system's signal numbering. - Similarly, ``enum target_signal'' is named incorrectly, ``enum + Similarly, ``enum gdb_signal'' is named incorrectly, ``enum gdb_signal'' would probably be better as it is refering to GDB's internal representation of a target operating system's signal. */ -extern enum target_signal target_signal_from_host (int); -extern int target_signal_to_host (enum target_signal); +extern enum gdb_signal gdb_signal_from_host (int); +extern int gdb_signal_to_host (enum gdb_signal); /* Return the string for a signal. */ -extern const char *target_signal_to_string (enum target_signal); +extern const char *gdb_signal_to_string (enum gdb_signal); /* Return the name (SIGHUP, etc.) for a signal. */ -extern const char *target_signal_to_name (enum target_signal); +extern const char *gdb_signal_to_name (enum gdb_signal); /* Given a name (SIGHUP, etc.), return its signal. */ -enum target_signal target_signal_from_name (const char *); +enum gdb_signal gdb_signal_from_name (const char *); #endif /* COMMON_GDB_SIGNALS_H */ diff --git a/contrib/gdb-7/gdb/gdb_stat.h b/contrib/gdb-7/gdb/common/gdb_stat.h similarity index 88% rename from contrib/gdb-7/gdb/gdb_stat.h rename to contrib/gdb-7/gdb/common/gdb_stat.h index a5d13e8af2..3e3c981947 100644 --- a/contrib/gdb-7/gdb/gdb_stat.h +++ b/contrib/gdb-7/gdb/common/gdb_stat.h @@ -1,5 +1,5 @@ /* Portable - Copyright (C) 1995, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1995-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,19 +22,6 @@ #include #include -#ifdef STAT_MACROS_BROKEN -#undef S_ISBLK -#undef S_ISCHR -#undef S_ISDIR -#undef S_ISREG -#undef S_ISFIFO -#undef S_ISLNK -#undef S_ISSOCK -#undef S_ISMPB -#undef S_ISMPC -#undef S_ISNWK -#endif - #if !defined(S_ISBLK) && defined(S_IFBLK) #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) #endif diff --git a/contrib/gdb-7/gdb/gdb_string.h b/contrib/gdb-7/gdb/common/gdb_string.h similarity index 95% rename from contrib/gdb-7/gdb/gdb_string.h rename to contrib/gdb-7/gdb/common/gdb_string.h index aa037dffcf..b7c52cf812 100644 --- a/contrib/gdb-7/gdb/gdb_string.h +++ b/contrib/gdb-7/gdb/common/gdb_string.h @@ -1,7 +1,6 @@ /* Portable - Copyright (C) 1995, 1998-2001, 2004, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1995-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/gdb_thread_db.h b/contrib/gdb-7/gdb/common/gdb_thread_db.h index 3f6b6c1adb..c95aa776fc 100644 --- a/contrib/gdb-7/gdb/common/gdb_thread_db.h +++ b/contrib/gdb-7/gdb/common/gdb_thread_db.h @@ -14,7 +14,7 @@ #else -/* Copyright (C) 1999-2000, 2007-2012 Free Software Foundation, Inc. +/* Copyright (C) 1999-2013 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 diff --git a/contrib/gdb-7/gdb/common/gdb_vecs.c b/contrib/gdb-7/gdb/common/gdb_vecs.c new file mode 100644 index 0000000000..8494aedaf4 --- /dev/null +++ b/contrib/gdb-7/gdb/common/gdb_vecs.c @@ -0,0 +1,93 @@ +/* Some commonly-used VEC types. + + Copyright (C) 2012-2013 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 . */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include "gdb_vecs.h" +#include "host-defs.h" + +/* Call xfree for each element of CHAR_PTR_VEC and final VEC_free for + CHAR_PTR_VEC itself. + + You must not modify CHAR_PTR_VEC after it got registered with this function + by make_cleanup as the CHAR_PTR_VEC base address may change on its updates. + Contrary to VEC_free this function does not (cannot) clear the pointer. */ + +void +free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec) +{ + int ix; + char *name; + + for (ix = 0; VEC_iterate (char_ptr, char_ptr_vec, ix, name); ++ix) + xfree (name); + VEC_free (char_ptr, char_ptr_vec); +} + +/* Extended version of dirnames_to_char_ptr_vec - additionally if *VECP is + non-NULL the new list elements from DIRNAMES are appended to the existing + *VECP list of entries. *VECP address will be updated by this call. */ + +void +dirnames_to_char_ptr_vec_append (VEC (char_ptr) **vecp, const char *dirnames) +{ + do + { + size_t this_len; + char *next_dir, *this_dir; + + next_dir = strchr (dirnames, DIRNAME_SEPARATOR); + if (next_dir == NULL) + this_len = strlen (dirnames); + else + { + this_len = next_dir - dirnames; + next_dir++; + } + + this_dir = xmalloc (this_len + 1); + memcpy (this_dir, dirnames, this_len); + this_dir[this_len] = '\0'; + VEC_safe_push (char_ptr, *vecp, this_dir); + + dirnames = next_dir; + } + while (dirnames != NULL); +} + +/* Split DIRNAMES by DIRNAME_SEPARATOR delimiter and return a list of all the + elements in their original order. For empty string ("") DIRNAMES return + list of one empty string ("") element. + + You may modify the returned strings. + Read free_char_ptr_vec for its cleanup. */ + +VEC (char_ptr) * +dirnames_to_char_ptr_vec (const char *dirnames) +{ + VEC (char_ptr) *retval = NULL; + + dirnames_to_char_ptr_vec_append (&retval, dirnames); + + return retval; +} diff --git a/contrib/gdb-7/gdb/mi/mi-main.h b/contrib/gdb-7/gdb/common/gdb_vecs.h similarity index 53% copy from contrib/gdb-7/gdb/mi/mi-main.h copy to contrib/gdb-7/gdb/common/gdb_vecs.h index beac2cde97..1b05b0c8f1 100644 --- a/contrib/gdb-7/gdb/mi/mi-main.h +++ b/contrib/gdb-7/gdb/common/gdb_vecs.h @@ -1,6 +1,6 @@ -/* MI Internal Functions for GDB, the GNU debugger. +/* Some commonly-used VEC types. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2012-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,22 +17,26 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef MI_MAIN_H -#define MI_MAIN_H +#ifndef GDB_VECS_H +#define GDB_VECS_H -extern void mi_load_progress (const char *section_name, - unsigned long sent_so_far, - unsigned long total_section, - unsigned long total_sent, - unsigned long grand_total); +#include "vec.h" -extern void mi_print_timing_maybe (void); +typedef char *char_ptr; +typedef const char *const_char_ptr; -extern char *current_token; +DEF_VEC_P (char_ptr); -extern int running_result_record_printed; -extern int mi_proceeded; -extern int mi_suppress_breakpoint_notifications; +DEF_VEC_P (const_char_ptr); -#endif +extern void free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec); +extern struct cleanup * + make_cleanup_free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec); + +extern void dirnames_to_char_ptr_vec_append (VEC (char_ptr) **vecp, + const char *dirnames); + +extern VEC (char_ptr) *dirnames_to_char_ptr_vec (const char *dirnames); + +#endif /* GDB_VECS_H */ diff --git a/contrib/gdb-7/gdb/gdb_wait.h b/contrib/gdb-7/gdb/common/gdb_wait.h similarity index 98% rename from contrib/gdb-7/gdb/gdb_wait.h rename to contrib/gdb-7/gdb/common/gdb_wait.h index 1d02f37374..1c234c4153 100644 --- a/contrib/gdb-7/gdb/gdb_wait.h +++ b/contrib/gdb-7/gdb/common/gdb_wait.h @@ -1,5 +1,5 @@ /* Standard wait macros. - Copyright (C) 2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/gdb_select.h b/contrib/gdb-7/gdb/common/host-defs.h similarity index 60% copy from contrib/gdb-7/gdb/gdb_select.h copy to contrib/gdb-7/gdb/common/host-defs.h index e55ae2297c..ac239b05a8 100644 --- a/contrib/gdb-7/gdb/gdb_select.h +++ b/contrib/gdb-7/gdb/common/host-defs.h @@ -1,6 +1,5 @@ -/* Slightly more portable version of . - - Copyright (C) 2006-2012 Free Software Foundation, Inc. +/* Basic host-specific definitions for GDB. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,20 +16,25 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#if !defined(GDB_SELECT_H) -#define GDB_SELECT_H +#ifndef HOST_DEFS_H +#define HOST_DEFS_H + +#ifdef __MSDOS__ +# define CANT_FORK +# define GLOBAL_CURDIR +# define DIRNAME_SEPARATOR ';' +#endif -#ifdef HAVE_SYS_SELECT_H -#include -#else -#include +#if !defined (__CYGWIN__) && defined (_WIN32) +# define DIRNAME_SEPARATOR ';' #endif -#ifdef USE_WIN32API -#include +#ifndef DIRNAME_SEPARATOR +#define DIRNAME_SEPARATOR ':' #endif -extern int gdb_select (int n, fd_set *readfds, fd_set *writefds, - fd_set *exceptfds, struct timeval *timeout); +#ifndef SLASH_STRING +#define SLASH_STRING "/" +#endif -#endif /* !defined(GDB_SELECT_H) */ +#endif /* HOST_DEFS_H */ diff --git a/contrib/gdb-7/gdb/common/i386-xstate.h b/contrib/gdb-7/gdb/common/i386-xstate.h index 56a4d8fb6b..ed0a683168 100644 --- a/contrib/gdb-7/gdb/common/i386-xstate.h +++ b/contrib/gdb-7/gdb/common/i386-xstate.h @@ -1,6 +1,6 @@ /* Common code for i386 XSAVE extended state. - Copyright (C) 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/linux-btrace.c b/contrib/gdb-7/gdb/common/linux-btrace.c new file mode 100644 index 0000000000..ed0cb2445f --- /dev/null +++ b/contrib/gdb-7/gdb/common/linux-btrace.c @@ -0,0 +1,610 @@ +/* Linux-dependent part of branch trace support for GDB, and GDBserver. + + Copyright (C) 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + 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 . */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include "linux-btrace.h" +#include "common-utils.h" +#include "gdb_assert.h" +#include "regcache.h" +#include "gdbthread.h" + +#if HAVE_LINUX_PERF_EVENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* A branch trace record in perf_event. */ +struct perf_event_bts +{ + /* The linear address of the branch source. */ + uint64_t from; + + /* The linear address of the branch destination. */ + uint64_t to; +}; + +/* A perf_event branch trace sample. */ +struct perf_event_sample +{ + /* The perf_event sample header. */ + struct perf_event_header header; + + /* The perf_event branch tracing payload. */ + struct perf_event_bts bts; +}; + +/* Get the perf_event header. */ + +static inline volatile struct perf_event_mmap_page * +perf_event_header (struct btrace_target_info* tinfo) +{ + return tinfo->buffer; +} + +/* Get the size of the perf_event mmap buffer. */ + +static inline size_t +perf_event_mmap_size (const struct btrace_target_info *tinfo) +{ + /* The branch trace buffer is preceded by a configuration page. */ + return (tinfo->size + 1) * PAGE_SIZE; +} + +/* Get the size of the perf_event buffer. */ + +static inline size_t +perf_event_buffer_size (struct btrace_target_info* tinfo) +{ + return tinfo->size * PAGE_SIZE; +} + +/* Get the start address of the perf_event buffer. */ + +static inline const uint8_t * +perf_event_buffer_begin (struct btrace_target_info* tinfo) +{ + return ((const uint8_t *) tinfo->buffer) + PAGE_SIZE; +} + +/* Get the end address of the perf_event buffer. */ + +static inline const uint8_t * +perf_event_buffer_end (struct btrace_target_info* tinfo) +{ + return perf_event_buffer_begin (tinfo) + perf_event_buffer_size (tinfo); +} + +/* Check whether an address is in the kernel. */ + +static inline int +perf_event_is_kernel_addr (const struct btrace_target_info *tinfo, + uint64_t addr) +{ + uint64_t mask; + + /* If we don't know the size of a pointer, we can't check. Let's assume it's + not a kernel address in this case. */ + if (tinfo->ptr_bits == 0) + return 0; + + /* A bit mask for the most significant bit in an address. */ + mask = (uint64_t) 1 << (tinfo->ptr_bits - 1); + + /* Check whether the most significant bit in the address is set. */ + return (addr & mask) != 0; +} + +/* Check whether a perf event record should be skipped. */ + +static inline int +perf_event_skip_record (const struct btrace_target_info *tinfo, + const struct perf_event_bts *bts) +{ + /* The hardware may report branches from kernel into user space. Branches + from user into kernel space will be suppressed. We filter the former to + provide a consistent branch trace excluding kernel. */ + return perf_event_is_kernel_addr (tinfo, bts->from); +} + +/* Perform a few consistency checks on a perf event sample record. This is + meant to catch cases when we get out of sync with the perf event stream. */ + +static inline int +perf_event_sample_ok (const struct perf_event_sample *sample) +{ + if (sample->header.type != PERF_RECORD_SAMPLE) + return 0; + + if (sample->header.size != sizeof (*sample)) + return 0; + + return 1; +} + +/* Branch trace is collected in a circular buffer [begin; end) as pairs of from + and to addresses (plus a header). + + Start points into that buffer at the next sample position. + We read the collected samples backwards from start. + + While reading the samples, we convert the information into a list of blocks. + For two adjacent samples s1 and s2, we form a block b such that b.begin = + s1.to and b.end = s2.from. + + In case the buffer overflows during sampling, one sample may have its lower + part at the end and its upper part at the beginning of the buffer. */ + +static VEC (btrace_block_s) * +perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin, + const uint8_t *end, const uint8_t *start) +{ + VEC (btrace_block_s) *btrace = NULL; + struct perf_event_sample sample; + size_t read = 0, size = (end - begin); + struct btrace_block block = { 0, 0 }; + struct regcache *regcache; + + gdb_assert (begin <= start); + gdb_assert (start <= end); + + /* The first block ends at the current pc. */ +#ifdef GDBSERVER + regcache = get_thread_regcache (find_thread_ptid (tinfo->ptid), 1); +#else + regcache = get_thread_regcache (tinfo->ptid); +#endif + block.end = regcache_read_pc (regcache); + + /* The buffer may contain a partial record as its last entry (i.e. when the + buffer size is not a multiple of the sample size). */ + read = sizeof (sample) - 1; + + for (; read < size; read += sizeof (sample)) + { + const struct perf_event_sample *psample; + + /* Find the next perf_event sample in a backwards traversal. */ + start -= sizeof (sample); + + /* If we're still inside the buffer, we're done. */ + if (begin <= start) + psample = (const struct perf_event_sample *) start; + else + { + int missing; + + /* We're to the left of the ring buffer, we will wrap around and + reappear at the very right of the ring buffer. */ + + missing = (begin - start); + start = (end - missing); + + /* If the entire sample is missing, we're done. */ + if (missing == sizeof (sample)) + psample = (const struct perf_event_sample *) start; + else + { + uint8_t *stack; + + /* The sample wrapped around. The lower part is at the end and + the upper part is at the beginning of the buffer. */ + stack = (uint8_t *) &sample; + + /* Copy the two parts so we have a contiguous sample. */ + memcpy (stack, start, missing); + memcpy (stack + missing, begin, sizeof (sample) - missing); + + psample = &sample; + } + } + + if (!perf_event_sample_ok (psample)) + { + warning (_("Branch trace may be incomplete.")); + break; + } + + if (perf_event_skip_record (tinfo, &psample->bts)) + continue; + + /* We found a valid sample, so we can complete the current block. */ + block.begin = psample->bts.to; + + VEC_safe_push (btrace_block_s, btrace, &block); + + /* Start the next block. */ + block.end = psample->bts.from; + } + + return btrace; +} + +/* Check whether the kernel supports branch tracing. */ + +static int +kernel_supports_btrace (void) +{ + struct perf_event_attr attr; + pid_t child, pid; + int status, file; + + errno = 0; + child = fork (); + switch (child) + { + case -1: + warning (_("test branch tracing: cannot fork: %s."), strerror (errno)); + return 0; + + case 0: + status = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + if (status != 0) + { + warning (_("test branch tracing: cannot PTRACE_TRACEME: %s."), + strerror (errno)); + _exit (1); + } + + status = raise (SIGTRAP); + if (status != 0) + { + warning (_("test branch tracing: cannot raise SIGTRAP: %s."), + strerror (errno)); + _exit (1); + } + + _exit (1); + + default: + pid = waitpid (child, &status, 0); + if (pid != child) + { + warning (_("test branch tracing: bad pid %ld, error: %s."), + (long) pid, strerror (errno)); + return 0; + } + + if (!WIFSTOPPED (status)) + { + warning (_("test branch tracing: expected stop. status: %d."), + status); + return 0; + } + + memset (&attr, 0, sizeof (attr)); + + attr.type = PERF_TYPE_HARDWARE; + attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; + attr.sample_period = 1; + attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR; + attr.exclude_kernel = 1; + attr.exclude_hv = 1; + attr.exclude_idle = 1; + + file = syscall (SYS_perf_event_open, &attr, child, -1, -1, 0); + if (file >= 0) + close (file); + + kill (child, SIGKILL); + ptrace (PTRACE_KILL, child, NULL, NULL); + + pid = waitpid (child, &status, 0); + if (pid != child) + { + warning (_("test branch tracing: bad pid %ld, error: %s."), + (long) pid, strerror (errno)); + if (!WIFSIGNALED (status)) + warning (_("test branch tracing: expected killed. status: %d."), + status); + } + + return (file >= 0); + } +} + +/* Check whether an Intel cpu supports branch tracing. */ + +static int +intel_supports_btrace (void) +{ +#if defined __i386__ || defined __x86_64__ + unsigned int cpuid, model, family; + + __asm__ __volatile__ ("movl $1, %%eax;" + "cpuid;" + : "=a" (cpuid) + :: "%ebx", "%ecx", "%edx"); + + family = (cpuid >> 8) & 0xf; + model = (cpuid >> 4) & 0xf; + + switch (family) + { + case 0x6: + model += (cpuid >> 12) & 0xf0; + + switch (model) + { + case 0x1a: /* Nehalem */ + case 0x1f: + case 0x1e: + case 0x2e: + case 0x25: /* Westmere */ + case 0x2c: + case 0x2f: + case 0x2a: /* Sandy Bridge */ + case 0x2d: + case 0x3a: /* Ivy Bridge */ + + /* AAJ122: LBR, BTM, or BTS records may have incorrect branch + "from" information afer an EIST transition, T-states, C1E, or + Adaptive Thermal Throttling. */ + return 0; + } + } + + return 1; + +#else /* !defined __i386__ && !defined __x86_64__ */ + + return 0; + +#endif /* !defined __i386__ && !defined __x86_64__ */ +} + +/* Check whether the cpu supports branch tracing. */ + +static int +cpu_supports_btrace (void) +{ +#if defined __i386__ || defined __x86_64__ + char vendor[13]; + + __asm__ __volatile__ ("xorl %%ebx, %%ebx;" + "xorl %%ecx, %%ecx;" + "xorl %%edx, %%edx;" + "movl $0, %%eax;" + "cpuid;" + "movl %%ebx, %0;" + "movl %%edx, %1;" + "movl %%ecx, %2;" + : "=m" (vendor[0]), + "=m" (vendor[4]), + "=m" (vendor[8]) + : + : "%eax", "%ebx", "%ecx", "%edx"); + vendor[12] = '\0'; + + if (strcmp (vendor, "GenuineIntel") == 0) + return intel_supports_btrace (); + + /* Don't know about others. Let's assume they do. */ + return 1; + +#else /* !defined __i386__ && !defined __x86_64__ */ + + return 0; + +#endif /* !defined __i386__ && !defined __x86_64__ */ +} + +/* See linux-btrace.h. */ + +int +linux_supports_btrace (void) +{ + static int cached; + + if (cached == 0) + { + if (!kernel_supports_btrace ()) + cached = -1; + else if (!cpu_supports_btrace ()) + cached = -1; + else + cached = 1; + } + + return cached > 0; +} + +/* See linux-btrace.h. */ + +struct btrace_target_info * +linux_enable_btrace (ptid_t ptid) +{ + struct btrace_target_info *tinfo; + int pid; + + tinfo = xzalloc (sizeof (*tinfo)); + tinfo->ptid = ptid; + + tinfo->attr.size = sizeof (tinfo->attr); + tinfo->attr.type = PERF_TYPE_HARDWARE; + tinfo->attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; + tinfo->attr.sample_period = 1; + + /* We sample from and to address. */ + tinfo->attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR; + + tinfo->attr.exclude_kernel = 1; + tinfo->attr.exclude_hv = 1; + tinfo->attr.exclude_idle = 1; + + tinfo->ptr_bits = 0; + + pid = ptid_get_lwp (ptid); + if (pid == 0) + pid = ptid_get_pid (ptid); + + errno = 0; + tinfo->file = syscall (SYS_perf_event_open, &tinfo->attr, pid, -1, -1, 0); + if (tinfo->file < 0) + goto err; + + /* We hard-code the trace buffer size. + At some later time, we should make this configurable. */ + tinfo->size = 1; + tinfo->buffer = mmap (NULL, perf_event_mmap_size (tinfo), + PROT_READ, MAP_SHARED, tinfo->file, 0); + if (tinfo->buffer == MAP_FAILED) + goto err_file; + + return tinfo; + + err_file: + close (tinfo->file); + + err: + xfree (tinfo); + return NULL; +} + +/* See linux-btrace.h. */ + +int +linux_disable_btrace (struct btrace_target_info *tinfo) +{ + int errcode; + + errno = 0; + errcode = munmap (tinfo->buffer, perf_event_mmap_size (tinfo)); + if (errcode != 0) + return errno; + + close (tinfo->file); + xfree (tinfo); + + return 0; +} + +/* Check whether the branch trace has changed. */ + +static int +linux_btrace_has_changed (struct btrace_target_info *tinfo) +{ + volatile struct perf_event_mmap_page *header = perf_event_header (tinfo); + + return header->data_head != tinfo->data_head; +} + +/* See linux-btrace.h. */ + +VEC (btrace_block_s) * +linux_read_btrace (struct btrace_target_info *tinfo, + enum btrace_read_type type) +{ + VEC (btrace_block_s) *btrace = NULL; + volatile struct perf_event_mmap_page *header; + const uint8_t *begin, *end, *start; + unsigned long data_head, retries = 5; + size_t buffer_size; + + if (type == btrace_read_new && !linux_btrace_has_changed (tinfo)) + return NULL; + + header = perf_event_header (tinfo); + buffer_size = perf_event_buffer_size (tinfo); + + /* We may need to retry reading the trace. See below. */ + while (retries--) + { + data_head = header->data_head; + + /* If there's new trace, let's read it. */ + if (data_head != tinfo->data_head) + { + /* Data_head keeps growing; the buffer itself is circular. */ + begin = perf_event_buffer_begin (tinfo); + start = begin + data_head % buffer_size; + + if (data_head <= buffer_size) + end = start; + else + end = perf_event_buffer_end (tinfo); + + btrace = perf_event_read_bts (tinfo, begin, end, start); + } + + /* The stopping thread notifies its ptracer before it is scheduled out. + On multi-core systems, the debugger might therefore run while the + kernel might be writing the last branch trace records. + + Let's check whether the data head moved while we read the trace. */ + if (data_head == header->data_head) + break; + } + + tinfo->data_head = data_head; + + return btrace; +} + +#else /* !HAVE_LINUX_PERF_EVENT_H */ + +/* See linux-btrace.h. */ + +int +linux_supports_btrace (void) +{ + return 0; +} + +/* See linux-btrace.h. */ + +struct btrace_target_info * +linux_enable_btrace (ptid_t ptid) +{ + return NULL; +} + +/* See linux-btrace.h. */ + +int +linux_disable_btrace (struct btrace_target_info *tinfo) +{ + return ENOSYS; +} + +/* See linux-btrace.h. */ + +VEC (btrace_block_s) * +linux_read_btrace (struct btrace_target_info *tinfo, + enum btrace_read_type type) +{ + return NULL; +} + +#endif /* !HAVE_LINUX_PERF_EVENT_H */ diff --git a/contrib/gdb-7/gdb/common/linux-btrace.h b/contrib/gdb-7/gdb/common/linux-btrace.h new file mode 100644 index 0000000000..d4e8402d1c --- /dev/null +++ b/contrib/gdb-7/gdb/common/linux-btrace.h @@ -0,0 +1,77 @@ +/* Linux-dependent part of branch trace support for GDB, and GDBserver. + + Copyright (C) 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + 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 LINUX_BTRACE_H +#define LINUX_BTRACE_H + +#include "btrace-common.h" +#include "config.h" +#include "vec.h" +#include "ptid.h" +#include +#include + +#if HAVE_LINUX_PERF_EVENT_H +# include +#endif + +/* Branch trace target information per thread. */ +struct btrace_target_info +{ +#if HAVE_LINUX_PERF_EVENT_H + /* The Linux perf_event configuration for collecting the branch trace. */ + struct perf_event_attr attr; + + /* The ptid of this thread. */ + ptid_t ptid; + + /* The mmap configuration mapping the branch trace perf_event buffer. + + file .. the file descriptor + buffer .. the mmapped memory buffer + size .. the buffer's size in pages without the configuration page + data_head .. the data head from the last read */ + int file; + void *buffer; + size_t size; + unsigned long data_head; +#endif /* HAVE_LINUX_PERF_EVENT_H */ + + /* The size of a pointer in bits for this thread. + The information is used to identify kernel addresses in order to skip + records from/to kernel space. */ + int ptr_bits; +}; + +/* Check whether branch tracing is supported. */ +extern int linux_supports_btrace (void); + +/* Enable branch tracing for @ptid. */ +extern struct btrace_target_info *linux_enable_btrace (ptid_t ptid); + +/* Disable branch tracing and deallocate @tinfo. */ +extern int linux_disable_btrace (struct btrace_target_info *tinfo); + +/* Read branch trace data. */ +extern VEC (btrace_block_s) *linux_read_btrace (struct btrace_target_info *, + enum btrace_read_type); + +#endif /* LINUX_BTRACE_H */ diff --git a/contrib/gdb-7/gdb/common/linux-osdata.c b/contrib/gdb-7/gdb/common/linux-osdata.c index 4f97a22ea5..d55470b9fa 100644 --- a/contrib/gdb-7/gdb/common/linux-osdata.c +++ b/contrib/gdb-7/gdb/common/linux-osdata.c @@ -1,6 +1,6 @@ /* Linux-specific functions to retrieve OS data. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -26,8 +26,7 @@ #include "linux-osdata.h" #include -#include -#include +#include #include #include #include @@ -44,13 +43,29 @@ #include "buffer.h" #include "gdb_assert.h" #include "gdb_dirent.h" +#include "gdb_stat.h" + +/* Define PID_T to be a fixed size that is at least as large as pid_t, + so that reading pid values embedded in /proc works + consistently. */ + +typedef long long PID_T; + +/* Define TIME_T to be at least as large as time_t, so that reading + time values embedded in /proc works consistently. */ + +typedef long long TIME_T; + +#define MAX_PID_T_STRLEN (sizeof ("-9223372036854775808") - 1) + +/* Returns the CPU core that thread PTID is currently running on. */ + +/* Compute and return the processor core of a given thread. */ int linux_common_core_of_thread (ptid_t ptid) { - char filename[sizeof ("/proc//task//stat") - + 2 * 20 /* decimal digits for 2 numbers, max 2^64 bit each */ - + 1]; + char filename[sizeof ("/proc//task//stat") + 2 * MAX_PID_T_STRLEN]; FILE *f; char *content = NULL; char *p; @@ -59,8 +74,8 @@ linux_common_core_of_thread (ptid_t ptid) int i; int core; - sprintf (filename, "/proc/%d/task/%ld/stat", - ptid_get_pid (ptid), ptid_get_lwp (ptid)); + sprintf (filename, "/proc/%lld/task/%lld/stat", + (PID_T) ptid_get_pid (ptid), (PID_T) ptid_get_lwp (ptid)); f = fopen (filename, "r"); if (!f) return -1; @@ -102,10 +117,14 @@ linux_common_core_of_thread (ptid_t ptid) return core; } +/* Finds the command-line of process PID and copies it into COMMAND. + At most MAXLEN characters are copied. If the command-line cannot + be found, PID is copied into command in text-form. */ + static void -command_from_pid (char *command, int maxlen, pid_t pid) +command_from_pid (char *command, int maxlen, PID_T pid) { - char *stat_path = xstrprintf ("/proc/%d/stat", pid); + char *stat_path = xstrprintf ("/proc/%lld/stat", pid); FILE *fp = fopen (stat_path, "r"); command[0] = '\0'; @@ -116,8 +135,8 @@ command_from_pid (char *command, int maxlen, pid_t pid) include/linux/sched.h in the Linux kernel sources) plus two (for the brackets). */ char cmd[32]; - pid_t stat_pid; - int items_read = fscanf (fp, "%d %32s", &stat_pid, cmd); + PID_T stat_pid; + int items_read = fscanf (fp, "%lld %32s", &stat_pid, cmd); if (items_read == 2 && pid == stat_pid) { @@ -130,7 +149,7 @@ command_from_pid (char *command, int maxlen, pid_t pid) else { /* Return the PID if a /proc entry for the process cannot be found. */ - snprintf (command, maxlen, "%d", pid); + snprintf (command, maxlen, "%lld", pid); } command[maxlen - 1] = '\0'; /* Ensure string is null-terminated. */ @@ -138,13 +157,13 @@ command_from_pid (char *command, int maxlen, pid_t pid) xfree (stat_path); } -/* Returns the command-line of the process with the given PID. The returned - string needs to be freed using xfree after use. */ +/* Returns the command-line of the process with the given PID. The + returned string needs to be freed using xfree after use. */ static char * -commandline_from_pid (pid_t pid) +commandline_from_pid (PID_T pid) { - char *pathname = xstrprintf ("/proc/%d/cmdline", pid); + char *pathname = xstrprintf ("/proc/%lld/cmdline", pid); char *commandline = NULL; FILE *f = fopen (pathname, "r"); @@ -180,7 +199,8 @@ commandline_from_pid (pid_t pid) } else { - /* Return the command in square brackets if the command-line is empty. */ + /* Return the command in square brackets if the command-line + is empty. */ commandline = (char *) xmalloc (32); commandline[0] = '['; command_from_pid (commandline + 1, 31, pid); @@ -196,6 +216,9 @@ commandline_from_pid (pid_t pid) return commandline; } +/* Finds the user name for the user UID and copies it into USER. At + most MAXLEN characters are copied. */ + static void user_from_uid (char *user, int maxlen, uid_t uid) { @@ -204,19 +227,23 @@ user_from_uid (char *user, int maxlen, uid_t uid) if (pwentry) { strncpy (user, pwentry->pw_name, maxlen); - user[maxlen - 1] = '\0'; /* Ensure that the user name is null-terminated. */ + /* Ensure that the user name is null-terminated. */ + user[maxlen - 1] = '\0'; } else user[0] = '\0'; } +/* Finds the owner of process PID and returns the user id in OWNER. + Returns 0 if the owner was found, -1 otherwise. */ + static int -get_process_owner (uid_t *owner, pid_t pid) +get_process_owner (uid_t *owner, PID_T pid) { struct stat statbuf; - char procentry[sizeof ("/proc/4294967295")]; + char procentry[sizeof ("/proc/") + MAX_PID_T_STRLEN]; - sprintf (procentry, "/proc/%d", pid); + sprintf (procentry, "/proc/%lld", pid); if (stat (procentry, &statbuf) == 0 && S_ISDIR (statbuf.st_mode)) { @@ -227,51 +254,34 @@ get_process_owner (uid_t *owner, pid_t pid) return -1; } -static int -get_number_of_cpu_cores (void) -{ - int cores = 0; - FILE *f = fopen ("/proc/cpuinfo", "r"); - - while (!feof (f)) - { - char buf[512]; - char *p = fgets (buf, sizeof (buf), f); - - if (p && strncmp (buf, "processor", 9) == 0) - ++cores; - } - - fclose (f); - - return cores; -} - -/* CORES points to an array of at least get_number_of_cpu_cores () elements. */ +/* Find the CPU cores used by process PID and return them in CORES. + CORES points to an array of at least sysconf(_SC_NPROCESSOR_ONLN) + elements. */ static int -get_cores_used_by_process (pid_t pid, int *cores) +get_cores_used_by_process (PID_T pid, int *cores) { - char taskdir[sizeof ("/proc/4294967295/task")]; + char taskdir[sizeof ("/proc/") + MAX_PID_T_STRLEN + sizeof ("/task") - 1]; DIR *dir; struct dirent *dp; int task_count = 0; - sprintf (taskdir, "/proc/%d/task", pid); + sprintf (taskdir, "/proc/%lld/task", pid); dir = opendir (taskdir); if (dir) { while ((dp = readdir (dir)) != NULL) { - pid_t tid; + PID_T tid; int core; if (!isdigit (dp->d_name[0]) - || NAMELEN (dp) > sizeof ("4294967295") - 1) + || NAMELEN (dp) > MAX_PID_T_STRLEN) continue; - tid = atoi (dp->d_name); - core = linux_common_core_of_thread (ptid_build (pid, tid, 0)); + sscanf (dp->d_name, "%lld", &tid); + core = linux_common_core_of_thread (ptid_build ((pid_t) pid, + (pid_t) tid, 0)); if (core >= 0) { @@ -309,12 +319,12 @@ linux_xfer_osdata_processes (gdb_byte *readbuf, dirp = opendir ("/proc"); if (dirp) { - const int num_cores = get_number_of_cpu_cores (); + const int num_cores = sysconf (_SC_NPROCESSORS_ONLN); struct dirent *dp; while ((dp = readdir (dirp)) != NULL) { - pid_t pid; + PID_T pid; uid_t owner; char user[UT_NAMESIZE]; char *command_line; @@ -324,10 +334,10 @@ linux_xfer_osdata_processes (gdb_byte *readbuf, int i; if (!isdigit (dp->d_name[0]) - || NAMELEN (dp) > sizeof ("4294967295") - 1) + || NAMELEN (dp) > MAX_PID_T_STRLEN) continue; - sscanf (dp->d_name, "%d", &pid); + sscanf (dp->d_name, "%lld", &pid); command_line = commandline_from_pid (pid); if (get_process_owner (&owner, pid) == 0) @@ -343,7 +353,7 @@ linux_xfer_osdata_processes (gdb_byte *readbuf, for (i = 0; i < num_cores && task_count > 0; ++i) if (cores[i]) { - char core_str[sizeof ("4294967205")]; + char core_str[sizeof ("4294967295")]; sprintf (core_str, "%d", i); strcat (cores_str, core_str); @@ -358,7 +368,7 @@ linux_xfer_osdata_processes (gdb_byte *readbuf, buffer_xml_printf ( &buffer, "" - "%d" + "%lld" "%s" "%s" "%s" @@ -396,6 +406,160 @@ linux_xfer_osdata_processes (gdb_byte *readbuf, return len; } +/* Auxiliary function used by qsort to sort processes by process + group. Compares two processes with ids PROCESS1 and PROCESS2. + PROCESS1 comes before PROCESS2 if it has a lower process group id. + If they belong to the same process group, PROCESS1 comes before + PROCESS2 if it has a lower process id or is the process group + leader. */ + +static int +compare_processes (const void *process1, const void *process2) +{ + PID_T pid1 = *((PID_T *) process1); + PID_T pid2 = *((PID_T *) process2); + PID_T pgid1 = *((PID_T *) process1 + 1); + PID_T pgid2 = *((PID_T *) process2 + 1); + + /* Sort by PGID. */ + if (pgid1 < pgid2) + return -1; + else if (pgid1 > pgid2) + return 1; + else + { + /* Process group leaders always come first, else sort by PID. */ + if (pid1 == pgid1) + return -1; + else if (pid2 == pgid2) + return 1; + else if (pid1 < pid2) + return -1; + else if (pid1 > pid2) + return 1; + else + return 0; + } +} + +/* Collect all process groups from /proc. */ + +static LONGEST +linux_xfer_osdata_processgroups (gdb_byte *readbuf, + ULONGEST offset, LONGEST len) +{ + /* We make the process list snapshot when the object starts to be read. */ + static const char *buf; + static LONGEST len_avail = -1; + static struct buffer buffer; + + if (offset == 0) + { + DIR *dirp; + + if (len_avail != -1 && len_avail != 0) + buffer_free (&buffer); + len_avail = 0; + buf = NULL; + buffer_init (&buffer); + buffer_grow_str (&buffer, "\n"); + + dirp = opendir ("/proc"); + if (dirp) + { + struct dirent *dp; + const size_t list_block_size = 512; + PID_T *process_list = (PID_T *) xmalloc (list_block_size * 2 * sizeof (PID_T)); + size_t process_count = 0; + size_t i; + + /* Build list consisting of PIDs followed by their + associated PGID. */ + while ((dp = readdir (dirp)) != NULL) + { + PID_T pid, pgid; + + if (!isdigit (dp->d_name[0]) + || NAMELEN (dp) > MAX_PID_T_STRLEN) + continue; + + sscanf (dp->d_name, "%lld", &pid); + pgid = getpgid (pid); + + if (pgid > 0) + { + process_list[2 * process_count] = pid; + process_list[2 * process_count + 1] = pgid; + ++process_count; + + /* Increase the size of the list if necessary. */ + if (process_count % list_block_size == 0) + process_list = (PID_T *) xrealloc ( + process_list, + (process_count + list_block_size) + * 2 * sizeof (PID_T)); + } + } + + closedir (dirp); + + /* Sort the process list. */ + qsort (process_list, process_count, 2 * sizeof (PID_T), + compare_processes); + + for (i = 0; i < process_count; ++i) + { + PID_T pid = process_list[2 * i]; + PID_T pgid = process_list[2 * i + 1]; + char leader_command[32]; + char *command_line; + + command_from_pid (leader_command, sizeof (leader_command), pgid); + command_line = commandline_from_pid (pid); + + buffer_xml_printf ( + &buffer, + "" + "%lld" + "%s" + "%lld" + "%s" + "", + pgid, + leader_command, + pid, + command_line ? command_line : ""); + + xfree (command_line); + } + + xfree (process_list); + } + + buffer_grow_str0 (&buffer, "\n"); + buf = buffer_finish (&buffer); + len_avail = strlen (buf); + } + + if (offset >= len_avail) + { + /* Done. Get rid of the buffer. */ + buffer_free (&buffer); + buf = NULL; + len_avail = 0; + return 0; + } + + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + + return len; +} + +/* Collect all the threads in /proc by iterating through processes and + then tasks within each process. */ + static LONGEST linux_xfer_osdata_threads (gdb_byte *readbuf, ULONGEST offset, LONGEST len) @@ -436,7 +600,7 @@ linux_xfer_osdata_threads (gdb_byte *readbuf, { DIR *dirp2; char *pathname; - pid_t pid; + PID_T pid; char command[32]; pathname = xstrprintf ("/proc/%s/task", dp->d_name); @@ -452,7 +616,7 @@ linux_xfer_osdata_threads (gdb_byte *readbuf, while ((dp2 = readdir (dirp2)) != NULL) { - pid_t tid; + PID_T tid; int core; if (!isdigit (dp2->d_name[0]) @@ -465,9 +629,9 @@ linux_xfer_osdata_threads (gdb_byte *readbuf, buffer_xml_printf ( &buffer, "" - "%d" + "%lld" "%s" - "%d" + "%lld" "%d" "", pid, @@ -507,13 +671,878 @@ linux_xfer_osdata_threads (gdb_byte *readbuf, return len; } +/* Collect all the open file descriptors found in /proc and put the details + found about them into READBUF. */ + +static LONGEST +linux_xfer_osdata_fds (gdb_byte *readbuf, + ULONGEST offset, LONGEST len) +{ + /* We make the process list snapshot when the object starts to be read. */ + static const char *buf; + static LONGEST len_avail = -1; + static struct buffer buffer; + + if (offset == 0) + { + DIR *dirp; + + if (len_avail != -1 && len_avail != 0) + buffer_free (&buffer); + len_avail = 0; + buf = NULL; + buffer_init (&buffer); + buffer_grow_str (&buffer, "\n"); + + dirp = opendir ("/proc"); + if (dirp) + { + struct dirent *dp; + + while ((dp = readdir (dirp)) != NULL) + { + struct stat statbuf; + char procentry[sizeof ("/proc/4294967295")]; + + if (!isdigit (dp->d_name[0]) + || NAMELEN (dp) > sizeof ("4294967295") - 1) + continue; + + sprintf (procentry, "/proc/%s", dp->d_name); + if (stat (procentry, &statbuf) == 0 + && S_ISDIR (statbuf.st_mode)) + { + char *pathname; + DIR *dirp2; + PID_T pid; + char command[32]; + + pid = atoi (dp->d_name); + command_from_pid (command, sizeof (command), pid); + + pathname = xstrprintf ("/proc/%s/fd", dp->d_name); + dirp2 = opendir (pathname); + + if (dirp2) + { + struct dirent *dp2; + + while ((dp2 = readdir (dirp2)) != NULL) + { + char *fdname; + char buf[1000]; + ssize_t rslt; + + if (!isdigit (dp2->d_name[0])) + continue; + + fdname = xstrprintf ("%s/%s", pathname, dp2->d_name); + rslt = readlink (fdname, buf, sizeof (buf) - 1); + if (rslt >= 0) + buf[rslt] = '\0'; + + buffer_xml_printf ( + &buffer, + "" + "%s" + "%s" + "%s" + "%s" + "", + dp->d_name, + command, + dp2->d_name, + (rslt >= 0 ? buf : dp2->d_name)); + } + + closedir (dirp2); + } + + xfree (pathname); + } + } + + closedir (dirp); + } + + buffer_grow_str0 (&buffer, "\n"); + buf = buffer_finish (&buffer); + len_avail = strlen (buf); + } + + if (offset >= len_avail) + { + /* Done. Get rid of the buffer. */ + buffer_free (&buffer); + buf = NULL; + len_avail = 0; + return 0; + } + + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + + return len; +} + +/* Returns the socket state STATE in textual form. */ + +static const char * +format_socket_state (unsigned char state) +{ + /* Copied from include/net/tcp_states.h in the Linux kernel sources. */ + enum { + TCP_ESTABLISHED = 1, + TCP_SYN_SENT, + TCP_SYN_RECV, + TCP_FIN_WAIT1, + TCP_FIN_WAIT2, + TCP_TIME_WAIT, + TCP_CLOSE, + TCP_CLOSE_WAIT, + TCP_LAST_ACK, + TCP_LISTEN, + TCP_CLOSING + }; + + switch (state) + { + case TCP_ESTABLISHED: + return "ESTABLISHED"; + case TCP_SYN_SENT: + return "SYN_SENT"; + case TCP_SYN_RECV: + return "SYN_RECV"; + case TCP_FIN_WAIT1: + return "FIN_WAIT1"; + case TCP_FIN_WAIT2: + return "FIN_WAIT2"; + case TCP_TIME_WAIT: + return "TIME_WAIT"; + case TCP_CLOSE: + return "CLOSE"; + case TCP_CLOSE_WAIT: + return "CLOSE_WAIT"; + case TCP_LAST_ACK: + return "LAST_ACK"; + case TCP_LISTEN: + return "LISTEN"; + case TCP_CLOSING: + return "CLOSING"; + default: + return "(unknown)"; + } +} + +union socket_addr + { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + }; + +/* Auxiliary function used by linux_xfer_osdata_isocket. Formats + information for all open internet sockets of type FAMILY on the + system into BUFFER. If TCP is set, only TCP sockets are processed, + otherwise only UDP sockets are processed. */ + +static void +print_sockets (unsigned short family, int tcp, struct buffer *buffer) +{ + const char *proc_file; + FILE *fp; + + if (family == AF_INET) + proc_file = tcp ? "/proc/net/tcp" : "/proc/net/udp"; + else if (family == AF_INET6) + proc_file = tcp ? "/proc/net/tcp6" : "/proc/net/udp6"; + else + return; + + fp = fopen (proc_file, "r"); + if (fp) + { + char buf[8192]; + + do + { + if (fgets (buf, sizeof (buf), fp)) + { + uid_t uid; + unsigned long tlen, inode; + int sl, timeout; + unsigned int local_port, remote_port, state; + unsigned int txq, rxq, trun, retn; + char local_address[NI_MAXHOST], remote_address[NI_MAXHOST]; + char extra[512]; + int result; + + result = sscanf (buf, + "%d: %33[0-9A-F]:%X %33[0-9A-F]:%X %X %X:%X %X:%lX %X %d %d %lu %512s\n", + &sl, + local_address, &local_port, + remote_address, &remote_port, + &state, + &txq, &rxq, + &trun, &tlen, + &retn, + &uid, + &timeout, + &inode, + extra); + + if (result == 15) + { + union socket_addr locaddr, remaddr; + size_t addr_size; + char user[UT_NAMESIZE]; + char local_service[NI_MAXSERV], remote_service[NI_MAXSERV]; + + if (family == AF_INET) + { + sscanf (local_address, "%X", + &locaddr.sin.sin_addr.s_addr); + sscanf (remote_address, "%X", + &remaddr.sin.sin_addr.s_addr); + + locaddr.sin.sin_port = htons (local_port); + remaddr.sin.sin_port = htons (remote_port); + + addr_size = sizeof (struct sockaddr_in); + } + else + { + sscanf (local_address, "%8X%8X%8X%8X", + locaddr.sin6.sin6_addr.s6_addr32, + locaddr.sin6.sin6_addr.s6_addr32 + 1, + locaddr.sin6.sin6_addr.s6_addr32 + 2, + locaddr.sin6.sin6_addr.s6_addr32 + 3); + sscanf (remote_address, "%8X%8X%8X%8X", + remaddr.sin6.sin6_addr.s6_addr32, + remaddr.sin6.sin6_addr.s6_addr32 + 1, + remaddr.sin6.sin6_addr.s6_addr32 + 2, + remaddr.sin6.sin6_addr.s6_addr32 + 3); + + locaddr.sin6.sin6_port = htons (local_port); + remaddr.sin6.sin6_port = htons (remote_port); + + locaddr.sin6.sin6_flowinfo = 0; + remaddr.sin6.sin6_flowinfo = 0; + locaddr.sin6.sin6_scope_id = 0; + remaddr.sin6.sin6_scope_id = 0; + + addr_size = sizeof (struct sockaddr_in6); + } + + locaddr.sa.sa_family = remaddr.sa.sa_family = family; + + result = getnameinfo (&locaddr.sa, addr_size, + local_address, sizeof (local_address), + local_service, sizeof (local_service), + NI_NUMERICHOST | NI_NUMERICSERV + | (tcp ? 0 : NI_DGRAM)); + if (result) + continue; + + result = getnameinfo (&remaddr.sa, addr_size, + remote_address, + sizeof (remote_address), + remote_service, + sizeof (remote_service), + NI_NUMERICHOST | NI_NUMERICSERV + | (tcp ? 0 : NI_DGRAM)); + if (result) + continue; + + user_from_uid (user, sizeof (user), uid); + + buffer_xml_printf ( + buffer, + "" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "", + local_address, + local_service, + remote_address, + remote_service, + format_socket_state (state), + user, + (family == AF_INET) ? "INET" : "INET6", + tcp ? "STREAM" : "DGRAM"); + } + } + } + while (!feof (fp)); + + fclose (fp); + } +} + +/* Collect data about internet sockets and write it into READBUF. */ + +static LONGEST +linux_xfer_osdata_isockets (gdb_byte *readbuf, + ULONGEST offset, LONGEST len) +{ + static const char *buf; + static LONGEST len_avail = -1; + static struct buffer buffer; + + if (offset == 0) + { + if (len_avail != -1 && len_avail != 0) + buffer_free (&buffer); + len_avail = 0; + buf = NULL; + buffer_init (&buffer); + buffer_grow_str (&buffer, "\n"); + + print_sockets (AF_INET, 1, &buffer); + print_sockets (AF_INET, 0, &buffer); + print_sockets (AF_INET6, 1, &buffer); + print_sockets (AF_INET6, 0, &buffer); + + buffer_grow_str0 (&buffer, "\n"); + buf = buffer_finish (&buffer); + len_avail = strlen (buf); + } + + if (offset >= len_avail) + { + /* Done. Get rid of the buffer. */ + buffer_free (&buffer); + buf = NULL; + len_avail = 0; + return 0; + } + + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + + return len; +} + +/* Converts the time SECONDS into textual form and copies it into a + buffer TIME, with at most MAXLEN characters copied. */ + +static void +time_from_time_t (char *time, int maxlen, TIME_T seconds) +{ + if (!seconds) + time[0] = '\0'; + else + { + time_t t = (time_t) seconds; + + strncpy (time, ctime (&t), maxlen); + time[maxlen - 1] = '\0'; + } +} + +/* Finds the group name for the group GID and copies it into GROUP. + At most MAXLEN characters are copied. */ + +static void +group_from_gid (char *group, int maxlen, gid_t gid) +{ + struct group *grentry = getgrgid (gid); + + if (grentry) + { + strncpy (group, grentry->gr_name, maxlen); + /* Ensure that the group name is null-terminated. */ + group[maxlen - 1] = '\0'; + } + else + group[0] = '\0'; +} + +/* Collect data about shared memory recorded in /proc and write it + into READBUF. */ + +static LONGEST +linux_xfer_osdata_shm (gdb_byte *readbuf, + ULONGEST offset, LONGEST len) +{ + static const char *buf; + static LONGEST len_avail = -1; + static struct buffer buffer; + + if (offset == 0) + { + FILE *fp; + + if (len_avail != -1 && len_avail != 0) + buffer_free (&buffer); + len_avail = 0; + buf = NULL; + buffer_init (&buffer); + buffer_grow_str (&buffer, "\n"); + + fp = fopen ("/proc/sysvipc/shm", "r"); + if (fp) + { + char buf[8192]; + + do + { + if (fgets (buf, sizeof (buf), fp)) + { + key_t key; + uid_t uid, cuid; + gid_t gid, cgid; + PID_T cpid, lpid; + int shmid, size, nattch; + TIME_T atime, dtime, ctime; + unsigned int perms; + int items_read; + + items_read = sscanf (buf, + "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld", + &key, &shmid, &perms, &size, + &cpid, &lpid, + &nattch, + &uid, &gid, &cuid, &cgid, + &atime, &dtime, &ctime); + + if (items_read == 14) + { + char user[UT_NAMESIZE], group[UT_NAMESIZE]; + char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE]; + char ccmd[32], lcmd[32]; + char atime_str[32], dtime_str[32], ctime_str[32]; + + user_from_uid (user, sizeof (user), uid); + group_from_gid (group, sizeof (group), gid); + user_from_uid (cuser, sizeof (cuser), cuid); + group_from_gid (cgroup, sizeof (cgroup), cgid); + + command_from_pid (ccmd, sizeof (ccmd), cpid); + command_from_pid (lcmd, sizeof (lcmd), lpid); + + time_from_time_t (atime_str, sizeof (atime_str), atime); + time_from_time_t (dtime_str, sizeof (dtime_str), dtime); + time_from_time_t (ctime_str, sizeof (ctime_str), ctime); + + buffer_xml_printf ( + &buffer, + "" + "%d" + "%d" + "%o" + "%d" + "%s" + "%s" + "%d" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "", + key, + shmid, + perms, + size, + ccmd, + lcmd, + nattch, + user, + group, + cuser, + cgroup, + atime_str, + dtime_str, + ctime_str); + } + } + } + while (!feof (fp)); + + fclose (fp); + } + + buffer_grow_str0 (&buffer, "\n"); + buf = buffer_finish (&buffer); + len_avail = strlen (buf); + } + + if (offset >= len_avail) + { + /* Done. Get rid of the buffer. */ + buffer_free (&buffer); + buf = NULL; + len_avail = 0; + return 0; + } + + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + + return len; +} + +/* Collect data about semaphores recorded in /proc and write it + into READBUF. */ + +static LONGEST +linux_xfer_osdata_sem (gdb_byte *readbuf, + ULONGEST offset, LONGEST len) +{ + static const char *buf; + static LONGEST len_avail = -1; + static struct buffer buffer; + + if (offset == 0) + { + FILE *fp; + + if (len_avail != -1 && len_avail != 0) + buffer_free (&buffer); + len_avail = 0; + buf = NULL; + buffer_init (&buffer); + buffer_grow_str (&buffer, "\n"); + + fp = fopen ("/proc/sysvipc/sem", "r"); + if (fp) + { + char buf[8192]; + + do + { + if (fgets (buf, sizeof (buf), fp)) + { + key_t key; + uid_t uid, cuid; + gid_t gid, cgid; + unsigned int perms, nsems; + int semid; + TIME_T otime, ctime; + int items_read; + + items_read = sscanf (buf, + "%d %d %o %u %d %d %d %d %lld %lld", + &key, &semid, &perms, &nsems, + &uid, &gid, &cuid, &cgid, + &otime, &ctime); + + if (items_read == 10) + { + char user[UT_NAMESIZE], group[UT_NAMESIZE]; + char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE]; + char otime_str[32], ctime_str[32]; + + user_from_uid (user, sizeof (user), uid); + group_from_gid (group, sizeof (group), gid); + user_from_uid (cuser, sizeof (cuser), cuid); + group_from_gid (cgroup, sizeof (cgroup), cgid); + + time_from_time_t (otime_str, sizeof (otime_str), otime); + time_from_time_t (ctime_str, sizeof (ctime_str), ctime); + + buffer_xml_printf ( + &buffer, + "" + "%d" + "%d" + "%o" + "%u" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "", + key, + semid, + perms, + nsems, + user, + group, + cuser, + cgroup, + otime_str, + ctime_str); + } + } + } + while (!feof (fp)); + + fclose (fp); + } + + buffer_grow_str0 (&buffer, "\n"); + buf = buffer_finish (&buffer); + len_avail = strlen (buf); + } + + if (offset >= len_avail) + { + /* Done. Get rid of the buffer. */ + buffer_free (&buffer); + buf = NULL; + len_avail = 0; + return 0; + } + + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + + return len; +} + +/* Collect data about message queues recorded in /proc and write it + into READBUF. */ + +static LONGEST +linux_xfer_osdata_msg (gdb_byte *readbuf, + ULONGEST offset, LONGEST len) +{ + static const char *buf; + static LONGEST len_avail = -1; + static struct buffer buffer; + + if (offset == 0) + { + FILE *fp; + + if (len_avail != -1 && len_avail != 0) + buffer_free (&buffer); + len_avail = 0; + buf = NULL; + buffer_init (&buffer); + buffer_grow_str (&buffer, "\n"); + + fp = fopen ("/proc/sysvipc/msg", "r"); + if (fp) + { + char buf[8192]; + + do + { + if (fgets (buf, sizeof (buf), fp)) + { + key_t key; + PID_T lspid, lrpid; + uid_t uid, cuid; + gid_t gid, cgid; + unsigned int perms, cbytes, qnum; + int msqid; + TIME_T stime, rtime, ctime; + int items_read; + + items_read = sscanf (buf, + "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld", + &key, &msqid, &perms, &cbytes, &qnum, + &lspid, &lrpid, &uid, &gid, &cuid, &cgid, + &stime, &rtime, &ctime); + + if (items_read == 14) + { + char user[UT_NAMESIZE], group[UT_NAMESIZE]; + char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE]; + char lscmd[32], lrcmd[32]; + char stime_str[32], rtime_str[32], ctime_str[32]; + + user_from_uid (user, sizeof (user), uid); + group_from_gid (group, sizeof (group), gid); + user_from_uid (cuser, sizeof (cuser), cuid); + group_from_gid (cgroup, sizeof (cgroup), cgid); + + command_from_pid (lscmd, sizeof (lscmd), lspid); + command_from_pid (lrcmd, sizeof (lrcmd), lrpid); + + time_from_time_t (stime_str, sizeof (stime_str), stime); + time_from_time_t (rtime_str, sizeof (rtime_str), rtime); + time_from_time_t (ctime_str, sizeof (ctime_str), ctime); + + buffer_xml_printf ( + &buffer, + "" + "%d" + "%d" + "%o" + "%u" + "%u" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "", + key, + msqid, + perms, + cbytes, + qnum, + lscmd, + lrcmd, + user, + group, + cuser, + cgroup, + stime_str, + rtime_str, + ctime_str); + } + } + } + while (!feof (fp)); + + fclose (fp); + } + + buffer_grow_str0 (&buffer, "\n"); + buf = buffer_finish (&buffer); + len_avail = strlen (buf); + } + + if (offset >= len_avail) + { + /* Done. Get rid of the buffer. */ + buffer_free (&buffer); + buf = NULL; + len_avail = 0; + return 0; + } + + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + + return len; +} + +/* Collect data about loaded kernel modules and write it into + READBUF. */ + +static LONGEST +linux_xfer_osdata_modules (gdb_byte *readbuf, + ULONGEST offset, LONGEST len) +{ + static const char *buf; + static LONGEST len_avail = -1; + static struct buffer buffer; + + if (offset == 0) + { + FILE *fp; + + if (len_avail != -1 && len_avail != 0) + buffer_free (&buffer); + len_avail = 0; + buf = NULL; + buffer_init (&buffer); + buffer_grow_str (&buffer, "\n"); + + fp = fopen ("/proc/modules", "r"); + if (fp) + { + char buf[8192]; + + do + { + if (fgets (buf, sizeof (buf), fp)) + { + char name[64], dependencies[256], status[16]; + unsigned int size; + unsigned long long address; + int uses; + int items_read; + + items_read = sscanf (buf, + "%64s %d %d %256s %16s 0x%llx", + name, &size, &uses, + dependencies, status, &address); + + if (items_read == 6) + buffer_xml_printf ( + &buffer, + "" + "%s" + "%u" + "%d" + "%s" + "%s" + "%llx" + "", + name, + size, + uses, + dependencies, + status, + address); + } + } + while (!feof (fp)); + + fclose (fp); + } + + buffer_grow_str0 (&buffer, "\n"); + buf = buffer_finish (&buffer); + len_avail = strlen (buf); + } + + if (offset >= len_avail) + { + /* Done. Get rid of the buffer. */ + buffer_free (&buffer); + buf = NULL; + len_avail = 0; + return 0; + } + + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + + return len; +} + struct osdata_type { char *type; + char *title; char *description; LONGEST (*getter) (gdb_byte *readbuf, ULONGEST offset, LONGEST len); } osdata_table[] = { - { "processes", "Listing of all processes", linux_xfer_osdata_processes }, - { "threads", "Listing of all threads", linux_xfer_osdata_threads }, + { "processes", "Processes", "Listing of all processes", + linux_xfer_osdata_processes }, + { "procgroups", "Process groups", "Listing of all process groups", + linux_xfer_osdata_processgroups }, + { "threads", "Threads", "Listing of all threads", + linux_xfer_osdata_threads }, + { "files", "File descriptors", "Listing of all file descriptors", + linux_xfer_osdata_fds }, + { "sockets", "Sockets", "Listing of all internet-domain sockets", + linux_xfer_osdata_isockets }, + { "shm", "Shared-memory regions", "Listing of all shared-memory regions", + linux_xfer_osdata_shm }, + { "semaphores", "Semaphores", "Listing of all semaphores", + linux_xfer_osdata_sem }, + { "msg", "Message queues", "Listing of all message queues", + linux_xfer_osdata_msg }, + { "modules", "Kernel modules", "Listing of all loaded kernel modules", + linux_xfer_osdata_modules }, { NULL, NULL, NULL } }; @@ -544,9 +1573,11 @@ linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf, "" "%s" "%s" + "%s" "", osdata_table[i].type, - osdata_table[i].description); + osdata_table[i].description, + osdata_table[i].title); buffer_grow_str0 (&buffer, "\n"); buf = buffer_finish (&buffer); diff --git a/contrib/gdb-7/gdb/common/linux-osdata.h b/contrib/gdb-7/gdb/common/linux-osdata.h index b99c0e4276..8e45efaec0 100644 --- a/contrib/gdb-7/gdb/common/linux-osdata.h +++ b/contrib/gdb-7/gdb/common/linux-osdata.h @@ -1,6 +1,6 @@ /* Linux-specific functions to retrieve OS data. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/linux-procfs.c b/contrib/gdb-7/gdb/common/linux-procfs.c index 421f36edb4..f5dccfd372 100644 --- a/contrib/gdb-7/gdb/common/linux-procfs.c +++ b/contrib/gdb-7/gdb/common/linux-procfs.c @@ -1,5 +1,5 @@ /* Linux-specific PROCFS manipulation routines. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -28,28 +28,93 @@ /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not found. */ -int -linux_proc_get_tgid (int lwpid) +static int +linux_proc_get_int (pid_t lwpid, const char *field) { + size_t field_len = strlen (field); FILE *status_file; char buf[100]; - int tgid = -1; + int retval = -1; snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid); status_file = fopen (buf, "r"); - if (status_file != NULL) + if (status_file == NULL) { - while (fgets (buf, sizeof (buf), status_file)) - { - if (strncmp (buf, "Tgid:", 5) == 0) - { - tgid = strtoul (buf + strlen ("Tgid:"), NULL, 10); - break; - } - } - - fclose (status_file); + warning (_("unable to open /proc file '%s'"), buf); + return -1; } - return tgid; + while (fgets (buf, sizeof (buf), status_file)) + if (strncmp (buf, field, field_len) == 0 && buf[field_len] == ':') + { + retval = strtol (&buf[field_len + 1], NULL, 10); + break; + } + + fclose (status_file); + return retval; +} + +/* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not + found. */ + +int +linux_proc_get_tgid (pid_t lwpid) +{ + return linux_proc_get_int (lwpid, "Tgid"); +} + +/* See linux-procfs.h. */ + +pid_t +linux_proc_get_tracerpid (pid_t lwpid) +{ + return linux_proc_get_int (lwpid, "TracerPid"); +} + +/* Return non-zero if 'State' of /proc/PID/status contains STATE. */ + +static int +linux_proc_pid_has_state (pid_t pid, const char *state) +{ + char buffer[100]; + FILE *procfile; + int retval; + int have_state; + + xsnprintf (buffer, sizeof (buffer), "/proc/%d/status", (int) pid); + procfile = fopen (buffer, "r"); + if (procfile == NULL) + { + warning (_("unable to open /proc file '%s'"), buffer); + return 0; + } + + have_state = 0; + while (fgets (buffer, sizeof (buffer), procfile) != NULL) + if (strncmp (buffer, "State:", 6) == 0) + { + have_state = 1; + break; + } + retval = (have_state && strstr (buffer, state) != NULL); + fclose (procfile); + return retval; +} + +/* Detect `T (stopped)' in `/proc/PID/status'. + Other states including `T (tracing stop)' are reported as false. */ + +int +linux_proc_pid_is_stopped (pid_t pid) +{ + return linux_proc_pid_has_state (pid, "T (stopped)"); +} + +/* See linux-procfs.h declaration. */ + +int +linux_proc_pid_is_zombie (pid_t pid) +{ + return linux_proc_pid_has_state (pid, "Z (zombie)"); } diff --git a/contrib/gdb-7/gdb/common/linux-procfs.h b/contrib/gdb-7/gdb/common/linux-procfs.h index a4ba4a1b48..267d32d925 100644 --- a/contrib/gdb-7/gdb/common/linux-procfs.h +++ b/contrib/gdb-7/gdb/common/linux-procfs.h @@ -1,5 +1,5 @@ /* Linux-specific PROCFS manipulation routines. - Copyright (C) 2011-2012 Free Software Foundation, Inc. + Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -24,6 +24,20 @@ /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not found. */ -extern int linux_proc_get_tgid (int lwpid); +extern int linux_proc_get_tgid (pid_t lwpid); + +/* Return the TracerPid of LWPID from /proc/pid/status. Returns -1 if not + found. */ + +extern pid_t linux_proc_get_tracerpid (pid_t lwpid); + +/* Detect `T (stopped)' in `/proc/PID/status'. + Other states including `T (tracing stop)' are reported as false. */ + +extern int linux_proc_pid_is_stopped (pid_t pid); + +/* Return non-zero if PID is a zombie. */ + +extern int linux_proc_pid_is_zombie (pid_t pid); #endif /* COMMON_LINUX_PROCFS_H */ diff --git a/contrib/gdb-7/gdb/common/linux-ptrace.c b/contrib/gdb-7/gdb/common/linux-ptrace.c new file mode 100644 index 0000000000..d5ac061ccb --- /dev/null +++ b/contrib/gdb-7/gdb/common/linux-ptrace.c @@ -0,0 +1,238 @@ +/* Linux-specific ptrace manipulation routines. + Copyright (C) 2012-2013 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 . */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#include "gdb_string.h" +#endif + +#include "linux-ptrace.h" +#include "linux-procfs.h" +#include "buffer.h" +#include "gdb_assert.h" +#include "gdb_wait.h" + +/* Find all possible reasons we could fail to attach PID and append these + newline terminated reason strings to initialized BUFFER. '\0' termination + of BUFFER must be done by the caller. */ + +void +linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer) +{ + pid_t tracerpid; + + tracerpid = linux_proc_get_tracerpid (pid); + if (tracerpid > 0) + buffer_xml_printf (buffer, _("warning: process %d is already traced " + "by process %d\n"), + (int) pid, (int) tracerpid); + + if (linux_proc_pid_is_zombie (pid)) + buffer_xml_printf (buffer, _("warning: process %d is a zombie " + "- the process has already terminated\n"), + (int) pid); +} + +#if defined __i386__ || defined __x86_64__ + +/* Address of the 'ret' instruction in asm code block below. */ +extern void (linux_ptrace_test_ret_to_nx_instr) (void); + +#include +#include +#include +#include + +#endif /* defined __i386__ || defined __x86_64__ */ + +/* Test broken off-trunk Linux kernel patchset for NX support on i386. It was + removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd. + + Test also x86_64 arch for PaX support. */ + +static void +linux_ptrace_test_ret_to_nx (void) +{ +#if defined __i386__ || defined __x86_64__ + pid_t child, got_pid; + gdb_byte *return_address, *pc; + long l; + int status, kill_status; + + return_address = mmap (NULL, 2, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (return_address == MAP_FAILED) + { + warning (_("linux_ptrace_test_ret_to_nx: Cannot mmap: %s"), + strerror (errno)); + return; + } + + /* Put there 'int3'. */ + *return_address = 0xcc; + + child = fork (); + switch (child) + { + case -1: + warning (_("linux_ptrace_test_ret_to_nx: Cannot fork: %s"), + strerror (errno)); + return; + + case 0: + l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + if (l != 0) + warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"), + strerror (errno)); + else + { +#if defined __i386__ + asm volatile ("pushl %0;" + ".globl linux_ptrace_test_ret_to_nx_instr;" + "linux_ptrace_test_ret_to_nx_instr:" + "ret" + : : "r" (return_address) : "%esp", "memory"); +#elif defined __x86_64__ + asm volatile ("pushq %0;" + ".globl linux_ptrace_test_ret_to_nx_instr;" + "linux_ptrace_test_ret_to_nx_instr:" + "ret" + : : "r" ((uint64_t) (uintptr_t) return_address) + : "%rsp", "memory"); +#else +# error "!__i386__ && !__x86_64__" +#endif + gdb_assert_not_reached ("asm block did not terminate"); + } + + _exit (1); + } + + errno = 0; + got_pid = waitpid (child, &status, 0); + if (got_pid != child) + { + warning (_("linux_ptrace_test_ret_to_nx: waitpid returned %ld: %s"), + (long) got_pid, strerror (errno)); + return; + } + + if (WIFSIGNALED (status)) + { + if (WTERMSIG (status) != SIGKILL) + warning (_("linux_ptrace_test_ret_to_nx: WTERMSIG %d is not SIGKILL!"), + (int) WTERMSIG (status)); + else + warning (_("Cannot call inferior functions, Linux kernel PaX " + "protection forbids return to non-executable pages!")); + return; + } + + if (!WIFSTOPPED (status)) + { + warning (_("linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"), + status); + return; + } + + /* We may get SIGSEGV due to missing PROT_EXEC of the return_address. */ + if (WSTOPSIG (status) != SIGTRAP && WSTOPSIG (status) != SIGSEGV) + { + warning (_("linux_ptrace_test_ret_to_nx: " + "WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"), + (int) WSTOPSIG (status)); + return; + } + + errno = 0; +#if defined __i386__ + l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (EIP * 4), NULL); +#elif defined __x86_64__ + l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (RIP * 8), NULL); +#else +# error "!__i386__ && !__x86_64__" +#endif + if (errno != 0) + { + warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_PEEKUSER: %s"), + strerror (errno)); + return; + } + pc = (void *) (uintptr_t) l; + + kill (child, SIGKILL); + ptrace (PTRACE_KILL, child, NULL, NULL); + + errno = 0; + got_pid = waitpid (child, &kill_status, 0); + if (got_pid != child) + { + warning (_("linux_ptrace_test_ret_to_nx: " + "PTRACE_KILL waitpid returned %ld: %s"), + (long) got_pid, strerror (errno)); + return; + } + if (!WIFSIGNALED (kill_status)) + { + warning (_("linux_ptrace_test_ret_to_nx: " + "PTRACE_KILL status %d is not WIFSIGNALED!"), + status); + return; + } + + /* + 1 is there as x86* stops after the 'int3' instruction. */ + if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1) + { + /* PASS */ + return; + } + + /* We may get SIGSEGV due to missing PROT_EXEC of the RETURN_ADDRESS page. */ + if (WSTOPSIG (status) == SIGSEGV && pc == return_address) + { + /* PASS */ + return; + } + + if ((void (*) (void)) pc != &linux_ptrace_test_ret_to_nx_instr) + warning (_("linux_ptrace_test_ret_to_nx: PC %p is neither near return " + "address %p nor is the return instruction %p!"), + pc, return_address, &linux_ptrace_test_ret_to_nx_instr); + else + warning (_("Cannot call inferior functions on this system - " + "Linux kernel with broken i386 NX (non-executable pages) " + "support detected!")); +#endif /* defined __i386__ || defined __x86_64__ */ +} + +/* Display possible problems on this system. Display them only once per GDB + execution. */ + +void +linux_ptrace_init_warnings (void) +{ + static int warned = 0; + + if (warned) + return; + warned = 1; + + linux_ptrace_test_ret_to_nx (); +} diff --git a/contrib/gdb-7/gdb/common/linux-ptrace.h b/contrib/gdb-7/gdb/common/linux-ptrace.h index 96ac3fb8b7..8f02c82ea0 100644 --- a/contrib/gdb-7/gdb/common/linux-ptrace.h +++ b/contrib/gdb-7/gdb/common/linux-ptrace.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2012 Free Software Foundation, Inc. +/* Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -18,6 +18,8 @@ #ifndef COMMON_LINUX_PTRACE_H #define COMMON_LINUX_PTRACE_H +struct buffer; + #include #ifndef PTRACE_GETSIGINFO @@ -65,4 +67,7 @@ #define __WALL 0x40000000 /* Wait for any child. */ #endif +extern void linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer); +extern void linux_ptrace_init_warnings (void); + #endif /* COMMON_LINUX_PTRACE_H */ diff --git a/contrib/gdb-7/gdb/common/ptid.c b/contrib/gdb-7/gdb/common/ptid.c index f5add4d606..506b5c2bef 100644 --- a/contrib/gdb-7/gdb/common/ptid.c +++ b/contrib/gdb-7/gdb/common/ptid.c @@ -1,6 +1,6 @@ /* The ptid_t type and common functions operating on it. - Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/ptid.h b/contrib/gdb-7/gdb/common/ptid.h index 243f4ab775..6a8dcbf83b 100644 --- a/contrib/gdb-7/gdb/common/ptid.h +++ b/contrib/gdb-7/gdb/common/ptid.h @@ -1,6 +1,6 @@ /* The ptid_t type and common functions operating on it. - Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/queue.h b/contrib/gdb-7/gdb/common/queue.h new file mode 100644 index 0000000000..14620271af --- /dev/null +++ b/contrib/gdb-7/gdb/common/queue.h @@ -0,0 +1,303 @@ +/* General queue data structure for GDB, the GNU debugger. + + Copyright (C) 2012-2013 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 QUEUE_H +#define QUEUE_H + +#include "libiberty.h" /* xmalloc */ +#include "gdb_assert.h" + +/* These macros implement functions and structs for a general queue. + Macro 'DEFINE_QUEUE_P(TYPEDEF)' is to define the new queue type for + TYPEDEF', and macro 'DECLARE_QUEUE_P' is to declare external queue + APIs. The character P indicates TYPEDEF is a pointer (P). The + counterpart on object (O) and integer (I) are not implemented. + + An example of their use would be, + + typedef struct foo + {} *foo_p; + + DEFINE_QUEUE_P (foo_p); + // A pointer to a queue of foo pointers. FOO_XFREE is a destructor + // function for foo instances in queue. + QUEUE(foo_p) *foo_queue = QUEUE_alloc (foo_p, foo_xfree); + + foo_p foo_var_p; + // Enqueue and Dequeue + QUEUE_enque (foo_p, foo_queue, foo_var_p); + foo_var_p = QUEUE_deque (foo_p, foo_queue); + + static int visit_foo (QUEUE (foo_p) *q, QUEUE_ITER (foo_p) *iter, + foo_p f, void *data) + { + return 1; + } + // Iterate over queue. + QUEUE_iterate (foo_p, foo_queue, visit_foo, ¶m); + + QUEUE_free (foo_p, foo_queue); // Free queue. */ + +/* Typical enqueue operation. Put V into queue Q. */ +#define QUEUE_enque(TYPE, Q, V) queue_ ## TYPE ## _enque ((Q), (V)) + +/* Typical dequeue operation. Return head element of queue Q and + remove it. Q must not be empty. */ +#define QUEUE_deque(TYPE, Q) queue_ ## TYPE ## _deque (Q) + +/* Return the head element, but don't remove it from the queue. + Q must not be empty. */ +#define QUEUE_peek(TYPE, Q) queue_ ## TYPE ## _peek (Q) + +/* Return true if queue Q is empty. */ +#define QUEUE_is_empty(TYPE, Q) queue_ ## TYPE ## _is_empty (Q) + +/* Allocate memory for queue. FREE_FUNC is a function to release the + data put in each queue element. */ +#define QUEUE_alloc(TYPE, FREE_FUNC) queue_ ## TYPE ## _alloc (FREE_FUNC) + +/* Length of queue Q. */ +#define QUEUE_length(TYPE, Q) queue_ ## TYPE ## _length (Q) + +/* Free queue Q. Q's free_func is called once for each element. */ +#define QUEUE_free(TYPE, Q) queue_ ## TYPE ## _free (Q) + +/* Iterate over elements in the queue Q and call function OPERATE on + each element. It is allowed to remove element by OPERATE. OPERATE + returns false to terminate the iteration and true to continue the + iteration. Return false if iteration is terminated by function + OPERATE, otherwise return true. */ +#define QUEUE_iterate(TYPE, Q, OPERATE, PARAM) \ + queue_ ## TYPE ## _iterate ((Q), (OPERATE), (PARAM)) + +/* Remove the element per the state of iterator ITER from queue Q. + Leave the caller to release the data in the queue element. */ +#define QUEUE_remove_elem(TYPE, Q, ITER) \ + queue_ ## TYPE ## _remove_elem ((Q), (ITER)) + +/* Define a new queue implementation. */ + +#define QUEUE(TYPE) struct queue_ ## TYPE +#define QUEUE_ELEM(TYPE) struct queue_elem_ ## TYPE +#define QUEUE_ITER(TYPE) struct queue_iter_ ## TYPE +#define QUEUE_ITER_FUNC(TYPE) queue_ ## TYPE ## _operate_func + +#define DEFINE_QUEUE_P(TYPE) \ +QUEUE_ELEM (TYPE) \ +{ \ + QUEUE_ELEM (TYPE) *next; \ + \ + TYPE data; \ +}; \ + \ +/* Queue iterator. */ \ +QUEUE_ITER (TYPE) \ +{ \ + /* The current element during traverse. */ \ + QUEUE_ELEM (TYPE) *p; \ + /* The previous element of P. */ \ + QUEUE_ELEM (TYPE) *prev; \ +}; \ + \ +QUEUE(TYPE) \ +{ \ + /* The head and tail of the queue. */ \ + QUEUE_ELEM (TYPE) *head; \ + QUEUE_ELEM (TYPE) *tail; \ + /* Function to release the data put in each \ + queue element. */ \ + void (*free_func) (TYPE); \ +}; \ + \ +void \ +queue_ ## TYPE ## _enque (QUEUE (TYPE) *q, TYPE v) \ +{ \ + QUEUE_ELEM (TYPE) *p \ + = xmalloc (sizeof (QUEUE_ELEM (TYPE))); \ + \ + gdb_assert (q != NULL); \ + p->data = v; \ + p->next = NULL; \ + if (q->tail == NULL) \ + { \ + q->tail = p; \ + q->head = p; \ + } \ + else \ + { \ + q->tail->next = p; \ + q->tail = p; \ + } \ +} \ + \ +TYPE \ +queue_ ## TYPE ## _deque (QUEUE (TYPE) *q) \ +{ \ + QUEUE_ELEM (TYPE) *p; \ + TYPE v; \ + \ + gdb_assert (q != NULL); \ + p = q->head; \ + gdb_assert (p != NULL); \ + \ + if (q->head == q->tail) \ + { \ + q->head = NULL; \ + q->tail = NULL; \ + } \ + else \ + q->head = q->head->next; \ + \ + v = p->data; \ + \ + xfree (p); \ + return v; \ +} \ + \ +TYPE \ +queue_ ## TYPE ## _peek (QUEUE (TYPE) *q) \ +{ \ + gdb_assert (q != NULL); \ + gdb_assert (q->head != NULL); \ + return q->head->data; \ +} \ + \ +int \ +queue_ ## TYPE ## _is_empty (QUEUE (TYPE) *q) \ +{ \ + gdb_assert (q != NULL); \ + return q->head == NULL; \ +} \ + \ +void \ +queue_ ## TYPE ## _remove_elem (QUEUE (TYPE) *q, \ + QUEUE_ITER (TYPE) *iter) \ +{ \ + gdb_assert (q != NULL); \ + gdb_assert (iter != NULL && iter->p != NULL); \ + \ + if (iter->p == q->head || iter->p == q->tail) \ + { \ + if (iter->p == q->head) \ + q->head = iter->p->next; \ + if (iter->p == q->tail) \ + q->tail = iter->prev; \ + } \ + else \ + iter->prev->next = iter->p->next; \ + \ + xfree (iter->p); \ + /* Indicate that ITER->p has been deleted from QUEUE q. */ \ + iter->p = NULL; \ +} \ + \ +int \ +queue_ ## TYPE ## _iterate (QUEUE (TYPE) *q, \ + QUEUE_ITER_FUNC (TYPE) operate, \ + void *data) \ +{ \ + QUEUE_ELEM (TYPE) *next = NULL; \ + QUEUE_ITER (TYPE) iter = { NULL, NULL }; \ + \ + gdb_assert (q != NULL); \ + \ + for (iter.p = q->head; iter.p != NULL; iter.p = next) \ + { \ + next = iter.p->next; \ + if (!operate (q, &iter, iter.p->data, data)) \ + return 0; \ + /* ITER.P was not deleted by function OPERATE. */ \ + if (iter.p != NULL) \ + iter.prev = iter.p; \ + } \ + return 1; \ +} \ + \ +QUEUE (TYPE) * \ +queue_ ## TYPE ## _alloc (void (*free_func) (TYPE)) \ +{ \ + QUEUE (TYPE) *q; \ + \ + q = (QUEUE (TYPE) *) xmalloc (sizeof (QUEUE (TYPE))); \ + q->head = NULL; \ + q->tail = NULL; \ + q->free_func = free_func; \ + return q; \ +} \ + \ +int \ +queue_ ## TYPE ## _length (QUEUE (TYPE) *q) \ +{ \ + QUEUE_ELEM (TYPE) *p; \ + int len = 0; \ + \ + gdb_assert (q != NULL); \ + \ + for (p = q->head; p != NULL; p = p->next) \ + len++; \ + \ + return len; \ +} \ + \ +void \ +queue_ ## TYPE ## _free (QUEUE (TYPE) *q) \ +{ \ + QUEUE_ELEM (TYPE) *p, *next; \ + \ + gdb_assert (q != NULL); \ + \ + for (p = q->head; p != NULL; p = next) \ + { \ + next = p->next; \ + if (q->free_func) \ + q->free_func (p->data); \ + xfree (p); \ + } \ + xfree (q); \ +} \ + +/* External declarations for queue functions. */ +#define DECLARE_QUEUE_P(TYPE) \ +QUEUE (TYPE); \ +QUEUE_ELEM (TYPE); \ +QUEUE_ITER (TYPE); \ +extern void \ + queue_ ## TYPE ## _enque (QUEUE (TYPE) *q, TYPE v); \ +extern TYPE \ + queue_ ## TYPE ## _deque (QUEUE (TYPE) *q); \ +extern int queue_ ## TYPE ## _is_empty (QUEUE (TYPE) *q); \ +extern QUEUE (TYPE) * \ + queue_ ## TYPE ## _alloc (void (*free_func) (TYPE)); \ +extern int queue_ ## TYPE ## _length (QUEUE (TYPE) *q); \ +extern TYPE \ + queue_ ## TYPE ## _peek (QUEUE (TYPE) *q); \ +extern void queue_ ## TYPE ## _free (QUEUE (TYPE) *q); \ +typedef int QUEUE_ITER_FUNC(TYPE) (QUEUE (TYPE) *, \ + QUEUE_ITER (TYPE) *, \ + TYPE, \ + void *); \ +extern int \ + queue_ ## TYPE ## _iterate (QUEUE (TYPE) *q, \ + QUEUE_ITER_FUNC (TYPE) operate, \ + void *); \ +extern void \ + queue_ ## TYPE ## _remove_elem (QUEUE (TYPE) *q, \ + QUEUE_ITER (TYPE) *iter); \ + +#endif /* QUEUE_H */ diff --git a/contrib/gdb-7/gdb/common/signals.c b/contrib/gdb-7/gdb/common/signals.c index 75699dbd5a..4b3b951bdd 100644 --- a/contrib/gdb-7/gdb/common/signals.c +++ b/contrib/gdb-7/gdb/common/signals.c @@ -1,5 +1,5 @@ /* Target signal translation functions for GDB. - Copyright (C) 1990-2003, 2006-2012 Free Software Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. Contributed by Cygnus Support. This file is part of GDB. @@ -47,7 +47,7 @@ struct gdbarch; #endif /* This table must match in order and size the signals in enum - target_signal. */ + gdb_signal. */ static const struct { const char *name; @@ -62,19 +62,19 @@ static const struct { /* Return the string for a signal. */ const char * -target_signal_to_string (enum target_signal sig) +gdb_signal_to_string (enum gdb_signal sig) { - if ((int) sig >= TARGET_SIGNAL_FIRST && (int) sig <= TARGET_SIGNAL_LAST) + if ((int) sig >= GDB_SIGNAL_FIRST && (int) sig <= GDB_SIGNAL_LAST) return signals[sig].string; else - return signals[TARGET_SIGNAL_UNKNOWN].string; + return signals[GDB_SIGNAL_UNKNOWN].string; } /* Return the name for a signal. */ const char * -target_signal_to_name (enum target_signal sig) +gdb_signal_to_name (enum gdb_signal sig) { - if ((int) sig >= TARGET_SIGNAL_FIRST && (int) sig <= TARGET_SIGNAL_LAST + if ((int) sig >= GDB_SIGNAL_FIRST && (int) sig <= GDB_SIGNAL_LAST && signals[sig].name != NULL) return signals[sig].name; else @@ -84,24 +84,24 @@ target_signal_to_name (enum target_signal sig) } /* Given a name, return its signal. */ -enum target_signal -target_signal_from_name (const char *name) +enum gdb_signal +gdb_signal_from_name (const char *name) { - enum target_signal sig; + enum gdb_signal sig; /* It's possible we also should allow "SIGCLD" as well as "SIGCHLD" - for TARGET_SIGNAL_SIGCHLD. SIGIOT, on the other hand, is more + for GDB_SIGNAL_SIGCHLD. SIGIOT, on the other hand, is more questionable; seems like by now people should call it SIGABRT instead. */ /* This ugly cast brought to you by the native VAX compiler. */ - for (sig = TARGET_SIGNAL_HUP; - sig < TARGET_SIGNAL_LAST; - sig = (enum target_signal) ((int) sig + 1)) + for (sig = GDB_SIGNAL_HUP; + sig < GDB_SIGNAL_LAST; + sig = (enum gdb_signal) ((int) sig + 1)) if (signals[sig].name != NULL && strcmp (name, signals[sig].name) == 0) return sig; - return TARGET_SIGNAL_UNKNOWN; + return GDB_SIGNAL_UNKNOWN; } /* The following functions are to help certain targets deal @@ -109,198 +109,198 @@ target_signal_from_name (const char *name) a file called native-utils.c or unixwaitstatus-utils.c or whatever. */ /* Convert host signal to our signals. */ -enum target_signal -target_signal_from_host (int hostsig) +enum gdb_signal +gdb_signal_from_host (int hostsig) { /* A switch statement would make sense but would require special kludges to deal with the cases where more than one signal has the same number. */ if (hostsig == 0) - return TARGET_SIGNAL_0; + return GDB_SIGNAL_0; #if defined (SIGHUP) if (hostsig == SIGHUP) - return TARGET_SIGNAL_HUP; + return GDB_SIGNAL_HUP; #endif #if defined (SIGINT) if (hostsig == SIGINT) - return TARGET_SIGNAL_INT; + return GDB_SIGNAL_INT; #endif #if defined (SIGQUIT) if (hostsig == SIGQUIT) - return TARGET_SIGNAL_QUIT; + return GDB_SIGNAL_QUIT; #endif #if defined (SIGILL) if (hostsig == SIGILL) - return TARGET_SIGNAL_ILL; + return GDB_SIGNAL_ILL; #endif #if defined (SIGTRAP) if (hostsig == SIGTRAP) - return TARGET_SIGNAL_TRAP; + return GDB_SIGNAL_TRAP; #endif #if defined (SIGABRT) if (hostsig == SIGABRT) - return TARGET_SIGNAL_ABRT; + return GDB_SIGNAL_ABRT; #endif #if defined (SIGEMT) if (hostsig == SIGEMT) - return TARGET_SIGNAL_EMT; + return GDB_SIGNAL_EMT; #endif #if defined (SIGFPE) if (hostsig == SIGFPE) - return TARGET_SIGNAL_FPE; + return GDB_SIGNAL_FPE; #endif #if defined (SIGKILL) if (hostsig == SIGKILL) - return TARGET_SIGNAL_KILL; + return GDB_SIGNAL_KILL; #endif #if defined (SIGBUS) if (hostsig == SIGBUS) - return TARGET_SIGNAL_BUS; + return GDB_SIGNAL_BUS; #endif #if defined (SIGSEGV) if (hostsig == SIGSEGV) - return TARGET_SIGNAL_SEGV; + return GDB_SIGNAL_SEGV; #endif #if defined (SIGSYS) if (hostsig == SIGSYS) - return TARGET_SIGNAL_SYS; + return GDB_SIGNAL_SYS; #endif #if defined (SIGPIPE) if (hostsig == SIGPIPE) - return TARGET_SIGNAL_PIPE; + return GDB_SIGNAL_PIPE; #endif #if defined (SIGALRM) if (hostsig == SIGALRM) - return TARGET_SIGNAL_ALRM; + return GDB_SIGNAL_ALRM; #endif #if defined (SIGTERM) if (hostsig == SIGTERM) - return TARGET_SIGNAL_TERM; + return GDB_SIGNAL_TERM; #endif #if defined (SIGUSR1) if (hostsig == SIGUSR1) - return TARGET_SIGNAL_USR1; + return GDB_SIGNAL_USR1; #endif #if defined (SIGUSR2) if (hostsig == SIGUSR2) - return TARGET_SIGNAL_USR2; + return GDB_SIGNAL_USR2; #endif #if defined (SIGCLD) if (hostsig == SIGCLD) - return TARGET_SIGNAL_CHLD; + return GDB_SIGNAL_CHLD; #endif #if defined (SIGCHLD) if (hostsig == SIGCHLD) - return TARGET_SIGNAL_CHLD; + return GDB_SIGNAL_CHLD; #endif #if defined (SIGPWR) if (hostsig == SIGPWR) - return TARGET_SIGNAL_PWR; + return GDB_SIGNAL_PWR; #endif #if defined (SIGWINCH) if (hostsig == SIGWINCH) - return TARGET_SIGNAL_WINCH; + return GDB_SIGNAL_WINCH; #endif #if defined (SIGURG) if (hostsig == SIGURG) - return TARGET_SIGNAL_URG; + return GDB_SIGNAL_URG; #endif #if defined (SIGIO) if (hostsig == SIGIO) - return TARGET_SIGNAL_IO; + return GDB_SIGNAL_IO; #endif #if defined (SIGPOLL) if (hostsig == SIGPOLL) - return TARGET_SIGNAL_POLL; + return GDB_SIGNAL_POLL; #endif #if defined (SIGSTOP) if (hostsig == SIGSTOP) - return TARGET_SIGNAL_STOP; + return GDB_SIGNAL_STOP; #endif #if defined (SIGTSTP) if (hostsig == SIGTSTP) - return TARGET_SIGNAL_TSTP; + return GDB_SIGNAL_TSTP; #endif #if defined (SIGCONT) if (hostsig == SIGCONT) - return TARGET_SIGNAL_CONT; + return GDB_SIGNAL_CONT; #endif #if defined (SIGTTIN) if (hostsig == SIGTTIN) - return TARGET_SIGNAL_TTIN; + return GDB_SIGNAL_TTIN; #endif #if defined (SIGTTOU) if (hostsig == SIGTTOU) - return TARGET_SIGNAL_TTOU; + return GDB_SIGNAL_TTOU; #endif #if defined (SIGVTALRM) if (hostsig == SIGVTALRM) - return TARGET_SIGNAL_VTALRM; + return GDB_SIGNAL_VTALRM; #endif #if defined (SIGPROF) if (hostsig == SIGPROF) - return TARGET_SIGNAL_PROF; + return GDB_SIGNAL_PROF; #endif #if defined (SIGXCPU) if (hostsig == SIGXCPU) - return TARGET_SIGNAL_XCPU; + return GDB_SIGNAL_XCPU; #endif #if defined (SIGXFSZ) if (hostsig == SIGXFSZ) - return TARGET_SIGNAL_XFSZ; + return GDB_SIGNAL_XFSZ; #endif #if defined (SIGWIND) if (hostsig == SIGWIND) - return TARGET_SIGNAL_WIND; + return GDB_SIGNAL_WIND; #endif #if defined (SIGPHONE) if (hostsig == SIGPHONE) - return TARGET_SIGNAL_PHONE; + return GDB_SIGNAL_PHONE; #endif #if defined (SIGLOST) if (hostsig == SIGLOST) - return TARGET_SIGNAL_LOST; + return GDB_SIGNAL_LOST; #endif #if defined (SIGWAITING) if (hostsig == SIGWAITING) - return TARGET_SIGNAL_WAITING; + return GDB_SIGNAL_WAITING; #endif #if defined (SIGCANCEL) if (hostsig == SIGCANCEL) - return TARGET_SIGNAL_CANCEL; + return GDB_SIGNAL_CANCEL; #endif #if defined (SIGLWP) if (hostsig == SIGLWP) - return TARGET_SIGNAL_LWP; + return GDB_SIGNAL_LWP; #endif #if defined (SIGDANGER) if (hostsig == SIGDANGER) - return TARGET_SIGNAL_DANGER; + return GDB_SIGNAL_DANGER; #endif #if defined (SIGGRANT) if (hostsig == SIGGRANT) - return TARGET_SIGNAL_GRANT; + return GDB_SIGNAL_GRANT; #endif #if defined (SIGRETRACT) if (hostsig == SIGRETRACT) - return TARGET_SIGNAL_RETRACT; + return GDB_SIGNAL_RETRACT; #endif #if defined (SIGMSG) if (hostsig == SIGMSG) - return TARGET_SIGNAL_MSG; + return GDB_SIGNAL_MSG; #endif #if defined (SIGSOUND) if (hostsig == SIGSOUND) - return TARGET_SIGNAL_SOUND; + return GDB_SIGNAL_SOUND; #endif #if defined (SIGSAK) if (hostsig == SIGSAK) - return TARGET_SIGNAL_SAK; + return GDB_SIGNAL_SAK; #endif #if defined (SIGPRIO) if (hostsig == SIGPRIO) - return TARGET_SIGNAL_PRIO; + return GDB_SIGNAL_PRIO; #endif /* Mach exceptions. Assumes that the values for EXC_ are positive! */ @@ -331,37 +331,37 @@ target_signal_from_host (int hostsig) #if defined (SIGINFO) if (hostsig == SIGINFO) - return TARGET_SIGNAL_INFO; + return GDB_SIGNAL_INFO; #endif #if defined (REALTIME_LO) if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI) { - /* This block of TARGET_SIGNAL_REALTIME value is in order. */ + /* This block of GDB_SIGNAL_REALTIME value is in order. */ if (33 <= hostsig && hostsig <= 63) - return (enum target_signal) - (hostsig - 33 + (int) TARGET_SIGNAL_REALTIME_33); + return (enum gdb_signal) + (hostsig - 33 + (int) GDB_SIGNAL_REALTIME_33); else if (hostsig == 32) - return TARGET_SIGNAL_REALTIME_32; + return GDB_SIGNAL_REALTIME_32; else if (64 <= hostsig && hostsig <= 127) - return (enum target_signal) - (hostsig - 64 + (int) TARGET_SIGNAL_REALTIME_64); + return (enum gdb_signal) + (hostsig - 64 + (int) GDB_SIGNAL_REALTIME_64); else - error (_("GDB bug: target.c (target_signal_from_host): " + error (_("GDB bug: target.c (gdb_signal_from_host): " "unrecognized real-time signal")); } #endif - return TARGET_SIGNAL_UNKNOWN; + return GDB_SIGNAL_UNKNOWN; } -/* Convert a OURSIG (an enum target_signal) to the form used by the +/* Convert a OURSIG (an enum gdb_signal) to the form used by the target operating system (refered to as the ``host'') or zero if the equivalent host signal is not available. Set/clear OURSIG_OK accordingly. */ static int -do_target_signal_to_host (enum target_signal oursig, +do_gdb_signal_to_host (enum gdb_signal oursig, int *oursig_ok) { int retsig; @@ -372,79 +372,79 @@ do_target_signal_to_host (enum target_signal oursig, *oursig_ok = 1; switch (oursig) { - case TARGET_SIGNAL_0: + case GDB_SIGNAL_0: return 0; #if defined (SIGHUP) - case TARGET_SIGNAL_HUP: + case GDB_SIGNAL_HUP: return SIGHUP; #endif #if defined (SIGINT) - case TARGET_SIGNAL_INT: + case GDB_SIGNAL_INT: return SIGINT; #endif #if defined (SIGQUIT) - case TARGET_SIGNAL_QUIT: + case GDB_SIGNAL_QUIT: return SIGQUIT; #endif #if defined (SIGILL) - case TARGET_SIGNAL_ILL: + case GDB_SIGNAL_ILL: return SIGILL; #endif #if defined (SIGTRAP) - case TARGET_SIGNAL_TRAP: + case GDB_SIGNAL_TRAP: return SIGTRAP; #endif #if defined (SIGABRT) - case TARGET_SIGNAL_ABRT: + case GDB_SIGNAL_ABRT: return SIGABRT; #endif #if defined (SIGEMT) - case TARGET_SIGNAL_EMT: + case GDB_SIGNAL_EMT: return SIGEMT; #endif #if defined (SIGFPE) - case TARGET_SIGNAL_FPE: + case GDB_SIGNAL_FPE: return SIGFPE; #endif #if defined (SIGKILL) - case TARGET_SIGNAL_KILL: + case GDB_SIGNAL_KILL: return SIGKILL; #endif #if defined (SIGBUS) - case TARGET_SIGNAL_BUS: + case GDB_SIGNAL_BUS: return SIGBUS; #endif #if defined (SIGSEGV) - case TARGET_SIGNAL_SEGV: + case GDB_SIGNAL_SEGV: return SIGSEGV; #endif #if defined (SIGSYS) - case TARGET_SIGNAL_SYS: + case GDB_SIGNAL_SYS: return SIGSYS; #endif #if defined (SIGPIPE) - case TARGET_SIGNAL_PIPE: + case GDB_SIGNAL_PIPE: return SIGPIPE; #endif #if defined (SIGALRM) - case TARGET_SIGNAL_ALRM: + case GDB_SIGNAL_ALRM: return SIGALRM; #endif #if defined (SIGTERM) - case TARGET_SIGNAL_TERM: + case GDB_SIGNAL_TERM: return SIGTERM; #endif #if defined (SIGUSR1) - case TARGET_SIGNAL_USR1: + case GDB_SIGNAL_USR1: return SIGUSR1; #endif #if defined (SIGUSR2) - case TARGET_SIGNAL_USR2: + case GDB_SIGNAL_USR2: return SIGUSR2; #endif #if defined (SIGCHLD) || defined (SIGCLD) - case TARGET_SIGNAL_CHLD: + case GDB_SIGNAL_CHLD: #if defined (SIGCHLD) return SIGCHLD; #else @@ -452,111 +452,111 @@ do_target_signal_to_host (enum target_signal oursig, #endif #endif /* SIGCLD or SIGCHLD */ #if defined (SIGPWR) - case TARGET_SIGNAL_PWR: + case GDB_SIGNAL_PWR: return SIGPWR; #endif #if defined (SIGWINCH) - case TARGET_SIGNAL_WINCH: + case GDB_SIGNAL_WINCH: return SIGWINCH; #endif #if defined (SIGURG) - case TARGET_SIGNAL_URG: + case GDB_SIGNAL_URG: return SIGURG; #endif #if defined (SIGIO) - case TARGET_SIGNAL_IO: + case GDB_SIGNAL_IO: return SIGIO; #endif #if defined (SIGPOLL) - case TARGET_SIGNAL_POLL: + case GDB_SIGNAL_POLL: return SIGPOLL; #endif #if defined (SIGSTOP) - case TARGET_SIGNAL_STOP: + case GDB_SIGNAL_STOP: return SIGSTOP; #endif #if defined (SIGTSTP) - case TARGET_SIGNAL_TSTP: + case GDB_SIGNAL_TSTP: return SIGTSTP; #endif #if defined (SIGCONT) - case TARGET_SIGNAL_CONT: + case GDB_SIGNAL_CONT: return SIGCONT; #endif #if defined (SIGTTIN) - case TARGET_SIGNAL_TTIN: + case GDB_SIGNAL_TTIN: return SIGTTIN; #endif #if defined (SIGTTOU) - case TARGET_SIGNAL_TTOU: + case GDB_SIGNAL_TTOU: return SIGTTOU; #endif #if defined (SIGVTALRM) - case TARGET_SIGNAL_VTALRM: + case GDB_SIGNAL_VTALRM: return SIGVTALRM; #endif #if defined (SIGPROF) - case TARGET_SIGNAL_PROF: + case GDB_SIGNAL_PROF: return SIGPROF; #endif #if defined (SIGXCPU) - case TARGET_SIGNAL_XCPU: + case GDB_SIGNAL_XCPU: return SIGXCPU; #endif #if defined (SIGXFSZ) - case TARGET_SIGNAL_XFSZ: + case GDB_SIGNAL_XFSZ: return SIGXFSZ; #endif #if defined (SIGWIND) - case TARGET_SIGNAL_WIND: + case GDB_SIGNAL_WIND: return SIGWIND; #endif #if defined (SIGPHONE) - case TARGET_SIGNAL_PHONE: + case GDB_SIGNAL_PHONE: return SIGPHONE; #endif #if defined (SIGLOST) - case TARGET_SIGNAL_LOST: + case GDB_SIGNAL_LOST: return SIGLOST; #endif #if defined (SIGWAITING) - case TARGET_SIGNAL_WAITING: + case GDB_SIGNAL_WAITING: return SIGWAITING; #endif #if defined (SIGCANCEL) - case TARGET_SIGNAL_CANCEL: + case GDB_SIGNAL_CANCEL: return SIGCANCEL; #endif #if defined (SIGLWP) - case TARGET_SIGNAL_LWP: + case GDB_SIGNAL_LWP: return SIGLWP; #endif #if defined (SIGDANGER) - case TARGET_SIGNAL_DANGER: + case GDB_SIGNAL_DANGER: return SIGDANGER; #endif #if defined (SIGGRANT) - case TARGET_SIGNAL_GRANT: + case GDB_SIGNAL_GRANT: return SIGGRANT; #endif #if defined (SIGRETRACT) - case TARGET_SIGNAL_RETRACT: + case GDB_SIGNAL_RETRACT: return SIGRETRACT; #endif #if defined (SIGMSG) - case TARGET_SIGNAL_MSG: + case GDB_SIGNAL_MSG: return SIGMSG; #endif #if defined (SIGSOUND) - case TARGET_SIGNAL_SOUND: + case GDB_SIGNAL_SOUND: return SIGSOUND; #endif #if defined (SIGSAK) - case TARGET_SIGNAL_SAK: + case GDB_SIGNAL_SAK: return SIGSAK; #endif #if defined (SIGPRIO) - case TARGET_SIGNAL_PRIO: + case GDB_SIGNAL_PRIO: return SIGPRIO; #endif @@ -587,7 +587,7 @@ do_target_signal_to_host (enum target_signal oursig, #endif #if defined (SIGINFO) - case TARGET_SIGNAL_INFO: + case GDB_SIGNAL_INFO: return SIGINFO; #endif @@ -595,25 +595,25 @@ do_target_signal_to_host (enum target_signal oursig, #if defined (REALTIME_LO) retsig = 0; - if (oursig >= TARGET_SIGNAL_REALTIME_33 - && oursig <= TARGET_SIGNAL_REALTIME_63) + if (oursig >= GDB_SIGNAL_REALTIME_33 + && oursig <= GDB_SIGNAL_REALTIME_63) { /* This block of signals is continuous, and - TARGET_SIGNAL_REALTIME_33 is 33 by definition. */ - retsig = (int) oursig - (int) TARGET_SIGNAL_REALTIME_33 + 33; + GDB_SIGNAL_REALTIME_33 is 33 by definition. */ + retsig = (int) oursig - (int) GDB_SIGNAL_REALTIME_33 + 33; } - else if (oursig == TARGET_SIGNAL_REALTIME_32) + else if (oursig == GDB_SIGNAL_REALTIME_32) { - /* TARGET_SIGNAL_REALTIME_32 isn't contiguous with - TARGET_SIGNAL_REALTIME_33. It is 32 by definition. */ + /* GDB_SIGNAL_REALTIME_32 isn't contiguous with + GDB_SIGNAL_REALTIME_33. It is 32 by definition. */ retsig = 32; } - else if (oursig >= TARGET_SIGNAL_REALTIME_64 - && oursig <= TARGET_SIGNAL_REALTIME_127) + else if (oursig >= GDB_SIGNAL_REALTIME_64 + && oursig <= GDB_SIGNAL_REALTIME_127) { /* This block of signals is continuous, and - TARGET_SIGNAL_REALTIME_64 is 64 by definition. */ - retsig = (int) oursig - (int) TARGET_SIGNAL_REALTIME_64 + 64; + GDB_SIGNAL_REALTIME_64 is 64 by definition. */ + retsig = (int) oursig - (int) GDB_SIGNAL_REALTIME_64 + 64; } if (retsig >= REALTIME_LO && retsig < REALTIME_HI) @@ -626,68 +626,26 @@ do_target_signal_to_host (enum target_signal oursig, } int -target_signal_to_host_p (enum target_signal oursig) +gdb_signal_to_host_p (enum gdb_signal oursig) { int oursig_ok; - do_target_signal_to_host (oursig, &oursig_ok); + do_gdb_signal_to_host (oursig, &oursig_ok); return oursig_ok; } int -target_signal_to_host (enum target_signal oursig) +gdb_signal_to_host (enum gdb_signal oursig) { int oursig_ok; - int targ_signo = do_target_signal_to_host (oursig, &oursig_ok); + int targ_signo = do_gdb_signal_to_host (oursig, &oursig_ok); if (!oursig_ok) { /* The user might be trying to do "signal SIGSAK" where this system doesn't have SIGSAK. */ warning (_("Signal %s does not exist on this system."), - target_signal_to_name (oursig)); + gdb_signal_to_name (oursig)); return 0; } else return targ_signo; } - -#ifndef GDBSERVER - -/* In some circumstances we allow a command to specify a numeric - signal. The idea is to keep these circumstances limited so that - users (and scripts) develop portable habits. For comparison, - POSIX.2 `kill' requires that 1,2,3,6,9,14, and 15 work (and using a - numeric signal at all is obsolescent. We are slightly more - lenient and allow 1-15 which should match host signal numbers on - most systems. Use of symbolic signal names is strongly encouraged. */ - -enum target_signal -target_signal_from_command (int num) -{ - if (num >= 1 && num <= 15) - return (enum target_signal) num; - error (_("Only signals 1-15 are valid as numeric signals.\n\ -Use \"info signals\" for a list of symbolic signals.")); -} - -extern initialize_file_ftype _initialize_signals; /* -Wmissing-prototype */ - -void -_initialize_signals (void) -{ - if (strcmp (signals[TARGET_SIGNAL_LAST].string, "TARGET_SIGNAL_MAGIC") != 0) - internal_error (__FILE__, __LINE__, "failed internal consistency check"); -} - -int -default_target_signal_to_host (struct gdbarch *gdbarch, enum target_signal ts) -{ - return target_signal_to_host (ts); -} - -enum target_signal -default_target_signal_from_host (struct gdbarch *gdbarch, int signo) -{ - return target_signal_from_host (signo); -} - -#endif /* ! GDBSERVER */ diff --git a/contrib/gdb-7/gdb/vec.c b/contrib/gdb-7/gdb/common/vec.c similarity index 96% rename from contrib/gdb-7/gdb/vec.c rename to contrib/gdb-7/gdb/common/vec.c index 3793a6a39e..2a82afb9e3 100644 --- a/contrib/gdb-7/gdb/vec.c +++ b/contrib/gdb-7/gdb/common/vec.c @@ -1,5 +1,5 @@ /* Vector API for GDB. - Copyright (C) 2004-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. Contributed by Nathan Sidwell This file is part of GDB. @@ -17,7 +17,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#ifdef GDBSERVER +#include "server.h" +#else #include "defs.h" +#endif + #include "vec.h" struct vec_prefix diff --git a/contrib/gdb-7/gdb/vec.h b/contrib/gdb-7/gdb/common/vec.h similarity index 92% rename from contrib/gdb-7/gdb/vec.h rename to contrib/gdb-7/gdb/common/vec.h index 7ec27a1931..86564e716b 100644 --- a/contrib/gdb-7/gdb/vec.h +++ b/contrib/gdb-7/gdb/common/vec.h @@ -1,5 +1,5 @@ /* Vector API for GDB. - Copyright (C) 2004-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. Contributed by Nathan Sidwell This file is part of GDB. @@ -21,6 +21,7 @@ #define GDB_VEC_H #include + #include "gdb_string.h" #include "gdb_assert.h" @@ -209,6 +210,13 @@ #define VEC_copy(T,V) (VEC_OP(T,copy)(V)) +/* Merge two vectors. + VEC(T,A) *VEC_T_merge(VEC(T) *, VEC(T) *); + + Copy the live elements of both vectors into a new vector. The new + and old vectors need not be allocated by the same mechanism. */ +#define VEC_merge(T,V1,V2) (VEC_OP(T,merge)(V1, V2)) + /* Determine if a vector has additional capacity. int VEC_T_space (VEC(T) *v,int reserve) @@ -460,6 +468,28 @@ static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ return new_vec_; \ } \ \ +static inline VEC(T) *VEC_OP (T,merge) (VEC(T) *vec1_, VEC(T) *vec2_) \ +{ \ + if (vec1_ && vec2_) \ + { \ + size_t len_ = vec1_->num + vec2_->num; \ + VEC (T) *new_vec_ = NULL; \ + \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *) \ + vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec1_->vec, sizeof (T) * vec1_->num); \ + memcpy (new_vec_->vec + vec1_->num, vec2_->vec, \ + sizeof (T) * vec2_->num); \ + \ + return new_vec_; \ + } \ + else \ + return VEC_copy (T, vec1_ ? vec1_ : vec2_); \ +} \ + \ static inline void VEC_OP (T,free) \ (VEC(T) **vec_) \ { \ @@ -740,6 +770,27 @@ static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ return new_vec_; \ } \ \ +static inline VEC(T) *VEC_OP (T,merge) (VEC(T) *vec1_, VEC(T) *vec2_) \ +{ \ + if (vec1_ && vec2_) \ + { \ + size_t len_ = vec1_->num + vec2_->num; \ + VEC (T) *new_vec_ = NULL; \ + \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *)(vec_p_reserve (NULL, -len_)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec1_->vec, sizeof (T) * vec1_->num); \ + memcpy (new_vec_->vec + vec1_->num, vec2_->vec, \ + sizeof (T) * vec2_->num); \ + \ + return new_vec_; \ + } \ + else \ + return VEC_copy (T, vec1_ ? vec1_ : vec2_); \ +} \ + \ static inline int VEC_OP (T,reserve) \ (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ { \ @@ -974,6 +1025,28 @@ static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ return new_vec_; \ } \ \ +static inline VEC(T) *VEC_OP (T,merge) (VEC(T) *vec1_, VEC(T) *vec2_) \ +{ \ + if (vec1_ && vec2_) \ + { \ + size_t len_ = vec1_->num + vec2_->num; \ + VEC (T) *new_vec_ = NULL; \ + \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *) \ + vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec1_->vec, sizeof (T) * vec1_->num); \ + memcpy (new_vec_->vec + vec1_->num, vec2_->vec, \ + sizeof (T) * vec2_->num); \ + \ + return new_vec_; \ + } \ + else \ + return VEC_copy (T, vec1_ ? vec1_ : vec2_); \ +} \ + \ static inline void VEC_OP (T,free) \ (VEC(T) **vec_) \ { \ diff --git a/contrib/gdb-7/gdb/common/xml-utils.c b/contrib/gdb-7/gdb/common/xml-utils.c index c486220201..89093cf8e5 100644 --- a/contrib/gdb-7/gdb/common/xml-utils.c +++ b/contrib/gdb-7/gdb/common/xml-utils.c @@ -1,6 +1,6 @@ /* Shared helper routines for manipulating XML. - Copyright (C) 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2006-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/common/xml-utils.h b/contrib/gdb-7/gdb/common/xml-utils.h index 8d38ea1cb1..ea4ab53e38 100644 --- a/contrib/gdb-7/gdb/common/xml-utils.h +++ b/contrib/gdb-7/gdb/common/xml-utils.h @@ -1,6 +1,6 @@ /* Shared helper routines for manipulating XML. - Copyright (C) 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2006-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/complaints.c b/contrib/gdb-7/gdb/complaints.c index 4df36ada86..739f5ec924 100644 --- a/contrib/gdb-7/gdb/complaints.c +++ b/contrib/gdb-7/gdb/complaints.c @@ -1,7 +1,6 @@ /* Support for complaint handling during symbol reading in GDB. - Copyright (C) 1990-1993, 1995, 1998-2000, 2002, 2004-2012 Free - Software Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/complaints.h b/contrib/gdb-7/gdb/complaints.h index 67ede19856..5d280942dc 100644 --- a/contrib/gdb-7/gdb/complaints.h +++ b/contrib/gdb-7/gdb/complaints.h @@ -1,7 +1,6 @@ /* Definitions for complaint handling during symbol reading in GDB. - Copyright (C) 1990-1992, 1995, 1998, 2000, 2002, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/completer.c b/contrib/gdb-7/gdb/completer.c index 48a4e463a7..3b14fc9423 100644 --- a/contrib/gdb-7/gdb/completer.c +++ b/contrib/gdb-7/gdb/completer.c @@ -1,5 +1,5 @@ /* Line completion stuff for GDB, the GNU debugger. - Copyright (C) 2000-2001, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -24,6 +24,7 @@ #include "language.h" #include "gdb_assert.h" #include "exceptions.h" +#include "gdb_signals.h" #include "cli/cli-decode.h" @@ -104,7 +105,7 @@ readline_line_completion_function (const char *text, int matches) /* This can be used for functions which don't want to complete on symbols but don't want to complete on anything else either. */ -char ** +VEC (char_ptr) * noop_completer (struct cmd_list_element *ignore, char *text, char *prefix) { @@ -112,19 +113,12 @@ noop_completer (struct cmd_list_element *ignore, } /* Complete on filenames. */ -char ** +VEC (char_ptr) * filename_completer (struct cmd_list_element *ignore, char *text, char *word) { int subsequent_name; - char **return_val; - int return_val_used; - int return_val_alloced; - - return_val_used = 0; - /* Small for testing. */ - return_val_alloced = 1; - return_val = (char **) xmalloc (return_val_alloced * sizeof (char *)); + VEC (char_ptr) *return_val = NULL; subsequent_name = 0; while (1) @@ -132,18 +126,8 @@ filename_completer (struct cmd_list_element *ignore, char *p, *q; p = rl_filename_completion_function (text, subsequent_name); - if (return_val_used >= return_val_alloced) - { - return_val_alloced *= 2; - return_val = - (char **) xrealloc (return_val, - return_val_alloced * sizeof (char *)); - } if (p == NULL) - { - return_val[return_val_used++] = p; - break; - } + break; /* We need to set subsequent_name to a non-zero value before the continue line below, because otherwise, if the first file seen by GDB is a backup file whose name ends in a `~', we @@ -159,13 +143,12 @@ filename_completer (struct cmd_list_element *ignore, if (word == text) /* Return exactly p. */ - return_val[return_val_used++] = p; + q = p; else if (word > text) { /* Return some portion of p. */ q = xmalloc (strlen (p) + 5); strcpy (q, p + (word - text)); - return_val[return_val_used++] = q; xfree (p); } else @@ -175,9 +158,9 @@ filename_completer (struct cmd_list_element *ignore, strncpy (q, word, text - word); q[text - word] = '\0'; strcat (q, p); - return_val[return_val_used++] = q; xfree (p); } + VEC_safe_push (char_ptr, return_val, q); } #if 0 /* There is no way to do this just long enough to affect quote @@ -199,13 +182,13 @@ filename_completer (struct cmd_list_element *ignore, This is intended to be used in commands that set breakpoints etc. */ -char ** +VEC (char_ptr) * location_completer (struct cmd_list_element *ignore, char *text, char *word) { - int n_syms = 0, n_files = 0; - char ** fn_list = NULL; - char ** list = NULL; + int n_syms, n_files, ix; + VEC (char_ptr) *fn_list = NULL; + VEC (char_ptr) *list = NULL; char *p; int quote_found = 0; int quoted = *text == '\'' || *text == '"'; @@ -216,7 +199,7 @@ location_completer (struct cmd_list_element *ignore, char *orig_text = text; size_t text_len; - /* Do we have an unquoted colon, as in "break foo.c::bar"? */ + /* Do we have an unquoted colon, as in "break foo.c:bar"? */ for (p = text; *p != '\0'; ++p) { if (*p == '\\' && p[1] == '\'') @@ -290,21 +273,26 @@ location_completer (struct cmd_list_element *ignore, fn_list = make_source_files_completion_list (text, text); } - /* How many completions do we have in both lists? */ - if (fn_list) - for ( ; fn_list[n_files]; n_files++) - ; - if (list) - for ( ; list[n_syms]; n_syms++) - ; + n_syms = VEC_length (char_ptr, list); + n_files = VEC_length (char_ptr, fn_list); + + /* Catenate fn_list[] onto the end of list[]. */ + if (!n_syms) + { + VEC_free (char_ptr, list); /* Paranoia. */ + list = fn_list; + fn_list = NULL; + } + else + { + for (ix = 0; VEC_iterate (char_ptr, fn_list, ix, p); ++ix) + VEC_safe_push (char_ptr, list, p); + VEC_free (char_ptr, fn_list); + } - /* Make list[] large enough to hold both lists, then catenate - fn_list[] onto the end of list[]. */ if (n_syms && n_files) { - list = xrealloc (list, (n_syms + n_files + 1) * sizeof (char *)); - memcpy (list + n_syms, fn_list, (n_files + 1) * sizeof (char *)); - xfree (fn_list); + /* Nothing. */ } else if (n_files) { @@ -323,76 +311,38 @@ location_completer (struct cmd_list_element *ignore, completion, because rl_complete will prepend "/foo/" to each candidate completion. The loop below removes that leading part. */ - for (n_files = 0; fn_list[n_files]; n_files++) + for (ix = 0; VEC_iterate (char_ptr, list, ix, p); ++ix) { - memmove (fn_list[n_files], fn_list[n_files] + (word - text), - strlen (fn_list[n_files]) + 1 - (word - text)); + memmove (p, p + (word - text), + strlen (p) + 1 - (word - text)); } - /* Return just the file-name list as the result. */ - list = fn_list; } else if (!n_syms) { /* No completions at all. As the final resort, try completing on the entire text as a symbol. */ list = make_symbol_completion_list (orig_text, word); - xfree (fn_list); } - else - xfree (fn_list); return list; } -/* Helper for expression_completer which recursively counts the number - of named fields and methods in a structure or union type. */ -static int -count_struct_fields (struct type *type) -{ - int i, result = 0; - - CHECK_TYPEDEF (type); - for (i = 0; i < TYPE_NFIELDS (type); ++i) - { - if (i < TYPE_N_BASECLASSES (type)) - result += count_struct_fields (TYPE_BASECLASS (type, i)); - else if (TYPE_FIELD_NAME (type, i)) - { - if (TYPE_FIELD_NAME (type, i)[0] != '\0') - ++result; - else if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_UNION) - { - /* Recurse into anonymous unions. */ - result += count_struct_fields (TYPE_FIELD_TYPE (type, i)); - } - } - } - - for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i) - { - if (TYPE_FN_FIELDLIST_NAME (type, i)) - ++result; - } - - return result; -} - /* Helper for expression_completer which recursively adds field and method names from TYPE, a struct or union type, to the array - OUTPUT. This function assumes that OUTPUT is correctly-sized. */ + OUTPUT. */ static void -add_struct_fields (struct type *type, int *nextp, char **output, +add_struct_fields (struct type *type, VEC (char_ptr) **output, char *fieldname, int namelen) { int i; int computed_type_name = 0; - char *type_name = NULL; + const char *type_name = NULL; CHECK_TYPEDEF (type); for (i = 0; i < TYPE_NFIELDS (type); ++i) { if (i < TYPE_N_BASECLASSES (type)) - add_struct_fields (TYPE_BASECLASS (type, i), nextp, + add_struct_fields (TYPE_BASECLASS (type, i), output, fieldname, namelen); else if (TYPE_FIELD_NAME (type, i)) { @@ -400,15 +350,13 @@ add_struct_fields (struct type *type, int *nextp, char **output, { if (! strncmp (TYPE_FIELD_NAME (type, i), fieldname, namelen)) - { - output[*nextp] = xstrdup (TYPE_FIELD_NAME (type, i)); - ++*nextp; - } + VEC_safe_push (char_ptr, *output, + xstrdup (TYPE_FIELD_NAME (type, i))); } else if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_UNION) { /* Recurse into anonymous unions. */ - add_struct_fields (TYPE_FIELD_TYPE (type, i), nextp, + add_struct_fields (TYPE_FIELD_TYPE (type, i), output, fieldname, namelen); } } @@ -416,7 +364,7 @@ add_struct_fields (struct type *type, int *nextp, char **output, for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i) { - char *name = TYPE_FN_FIELDLIST_NAME (type, i); + const char *name = TYPE_FN_FIELDLIST_NAME (type, i); if (name && ! strncmp (name, fieldname, namelen)) { @@ -427,10 +375,7 @@ add_struct_fields (struct type *type, int *nextp, char **output, } /* Omit constructors from the completion list. */ if (!type_name || strcmp (type_name, name)) - { - output[*nextp] = xstrdup (name); - ++*nextp; - } + VEC_safe_push (char_ptr, *output, xstrdup (name)); } } } @@ -438,20 +383,21 @@ add_struct_fields (struct type *type, int *nextp, char **output, /* Complete on expressions. Often this means completing on symbol names, but some language parsers also have support for completing field names. */ -char ** +VEC (char_ptr) * expression_completer (struct cmd_list_element *ignore, char *text, char *word) { struct type *type = NULL; char *fieldname, *p; volatile struct gdb_exception except; + enum type_code code = TYPE_CODE_UNDEF; /* Perform a tentative parse of the expression, to see whether a field completion is required. */ fieldname = NULL; TRY_CATCH (except, RETURN_MASK_ERROR) { - type = parse_field_expression (text, &fieldname); + type = parse_expression_for_completion (text, &fieldname, &code); } if (except.reason < 0) return NULL; @@ -469,17 +415,23 @@ expression_completer (struct cmd_list_element *ignore, if (TYPE_CODE (type) == TYPE_CODE_UNION || TYPE_CODE (type) == TYPE_CODE_STRUCT) { - int alloc = count_struct_fields (type); int flen = strlen (fieldname); - int out = 0; - char **result = (char **) xmalloc ((alloc + 1) * sizeof (char *)); + VEC (char_ptr) *result = NULL; - add_struct_fields (type, &out, result, fieldname, flen); - result[out] = NULL; + add_struct_fields (type, &result, fieldname, flen); xfree (fieldname); return result; } } + else if (fieldname && code != TYPE_CODE_UNDEF) + { + VEC (char_ptr) *result; + struct cleanup *cleanup = make_cleanup (xfree, fieldname); + + result = make_symbol_completion_type (fieldname, fieldname, code); + do_cleanups (cleanup); + return result; + } xfree (fieldname); /* Commands which complete on locations want to see the entire @@ -552,13 +504,14 @@ complete_line_internal_reason; once sub-command completions are exhausted, we simply return NULL. */ -static char ** +static VEC (char_ptr) * complete_line_internal (const char *text, char *line_buffer, int point, complete_line_internal_reason reason) { - char **list = NULL; + VEC (char_ptr) *list = NULL; char *tmp_command, *p; + int ignore_help_classes; /* Pointer within tmp_command which corresponds to text. */ char *word; struct cmd_list_element *c, *result_list; @@ -578,6 +531,9 @@ complete_line_internal (const char *text, tmp_command = (char *) alloca (point + 1); p = tmp_command; + /* The help command should complete help aliases. */ + ignore_help_classes = reason != handle_help; + strncpy (tmp_command, line_buffer, point); tmp_command[point] = '\0'; /* Since text always contains some number of characters leading up @@ -594,7 +550,7 @@ complete_line_internal (const char *text, } else { - c = lookup_cmd_1 (&p, cmdlist, &result_list, 1); + c = lookup_cmd_1 (&p, cmdlist, &result_list, ignore_help_classes); } /* Move p up to the next interesting thing. */ @@ -635,12 +591,13 @@ complete_line_internal (const char *text, { if (reason != handle_brkchars) list = complete_on_cmdlist (*result_list->prefixlist, p, - word); + word, ignore_help_classes); } else { if (reason != handle_brkchars) - list = complete_on_cmdlist (cmdlist, p, word); + list = complete_on_cmdlist (cmdlist, p, word, + ignore_help_classes); } /* Ensure that readline does the right thing with respect to inserting quotes. */ @@ -666,7 +623,8 @@ complete_line_internal (const char *text, /* It is a prefix command; what comes after it is a subcommand (e.g. "info "). */ if (reason != handle_brkchars) - list = complete_on_cmdlist (*c->prefixlist, p, word); + list = complete_on_cmdlist (*c->prefixlist, p, word, + ignore_help_classes); /* Ensure that readline does the right thing with respect to inserting quotes. */ @@ -737,7 +695,8 @@ complete_line_internal (const char *text, } if (reason != handle_brkchars) - list = complete_on_cmdlist (result_list, q, word); + list = complete_on_cmdlist (result_list, q, word, + ignore_help_classes); /* Ensure that readline does the right thing with respect to inserting quotes. */ @@ -794,9 +753,9 @@ complete_line_internal (const char *text, return list; } -/* Generate completions all at once. Returns a NULL-terminated array - of strings. Both the array and each element are allocated with - xmalloc. It can also return NULL if there are no completions. +/* Generate completions all at once. Returns a vector of strings. + Each element is allocated with xmalloc. It can also return NULL if + there are no completions. TEXT is the caller's idea of the "word" we are looking at. @@ -806,7 +765,7 @@ complete_line_internal (const char *text, POINT is the offset in that line of the cursor. You should pretend that the line ends at POINT. */ -char ** +VEC (char_ptr) * complete_line (const char *text, char *line_buffer, int point) { return complete_line_internal (text, line_buffer, @@ -814,7 +773,7 @@ complete_line (const char *text, char *line_buffer, int point) } /* Complete on command names. Used by "help". */ -char ** +VEC (char_ptr) * command_completer (struct cmd_list_element *ignore, char *text, char *word) { @@ -822,13 +781,43 @@ command_completer (struct cmd_list_element *ignore, strlen (text), handle_help); } +/* Complete on signals. */ + +VEC (char_ptr) * +signal_completer (struct cmd_list_element *ignore, + char *text, char *word) +{ + VEC (char_ptr) *return_val = NULL; + size_t len = strlen (word); + enum gdb_signal signum; + const char *signame; + + for (signum = GDB_SIGNAL_FIRST; signum != GDB_SIGNAL_LAST; ++signum) + { + /* Can't handle this, so skip it. */ + if (signum == GDB_SIGNAL_0) + continue; + + signame = gdb_signal_to_name (signum); + + /* Ignore the unknown signal case. */ + if (!signame || strcmp (signame, "?") == 0) + continue; + + if (strncasecmp (signame, word, len) == 0) + VEC_safe_push (char_ptr, return_val, xstrdup (signame)); + } + + return return_val; +} + /* Get the list of chars that are considered as word breaks for the current command. */ char * gdb_completion_word_break_characters (void) { - char **list; + VEC (char_ptr) *list; list = complete_line_internal (rl_line_buffer, rl_line_buffer, rl_point, handle_brkchars); @@ -861,7 +850,7 @@ static char * line_completion_function (const char *text, int matches, char *line_buffer, int point) { - static char **list = (char **) NULL; /* Cache of completions. */ + static VEC (char_ptr) *list = NULL; /* Cache of completions. */ static int index; /* Next cached completion. */ char *output = NULL; @@ -877,24 +866,22 @@ line_completion_function (const char *text, int matches, inside. This is because rl_complete_internal () frees the strings. As complete_line may abort by calling `error' clear LIST now. */ - xfree (list); - list = NULL; + VEC_free (char_ptr, list); } index = 0; list = complete_line (text, line_buffer, point); } /* If we found a list of potential completions during initialization - then dole them out one at a time. The vector of completions is - NULL terminated, so after returning the last one, return NULL - (and continue to do so) each time we are called after that, until - a new list is available. */ + then dole them out one at a time. After returning the last one, + return NULL (and continue to do so) each time we are called after + that, until a new list is available. */ if (list) { - output = list[index]; - if (output) + if (index < VEC_length (char_ptr, list)) { + output = VEC_index (char_ptr, list, index); index++; } } diff --git a/contrib/gdb-7/gdb/completer.h b/contrib/gdb-7/gdb/completer.h index 0f522459b1..f7fea6039a 100644 --- a/contrib/gdb-7/gdb/completer.h +++ b/contrib/gdb-7/gdb/completer.h @@ -1,5 +1,5 @@ /* Header for GDB line completion. - Copyright (C) 2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 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 @@ -17,27 +17,32 @@ #if !defined (COMPLETER_H) #define COMPLETER_H 1 -extern char **complete_line (const char *text, - char *line_buffer, - int point); +#include "gdb_vecs.h" + +extern VEC (char_ptr) *complete_line (const char *text, + char *line_buffer, + int point); extern char *readline_line_completion_function (const char *text, int matches); -extern char **noop_completer (struct cmd_list_element *, - char *, char *); +extern VEC (char_ptr) *noop_completer (struct cmd_list_element *, + char *, char *); + +extern VEC (char_ptr) *filename_completer (struct cmd_list_element *, + char *, char *); -extern char **filename_completer (struct cmd_list_element *, - char *, char *); +extern VEC (char_ptr) *expression_completer (struct cmd_list_element *, + char *, char *); -extern char **expression_completer (struct cmd_list_element *, - char *, char *); +extern VEC (char_ptr) *location_completer (struct cmd_list_element *, + char *, char *); -extern char **location_completer (struct cmd_list_element *, - char *, char *); +extern VEC (char_ptr) *command_completer (struct cmd_list_element *, + char *, char *); -extern char **command_completer (struct cmd_list_element *, - char *, char *); +extern VEC (char_ptr) *signal_completer (struct cmd_list_element *, + char *, char *); extern char *get_gdb_completer_quote_characters (void); diff --git a/contrib/gdb-7/gdb/config.in b/contrib/gdb-7/gdb/config.in index 4aff10db69..9e21325b1e 100644 --- a/contrib/gdb-7/gdb/config.in +++ b/contrib/gdb-7/gdb/config.in @@ -1,29 +1,16 @@ /* config.in. Generated from configure.ac by autoheader. */ -/* Define if the compiler is building for multiple architectures of Apple - platforms at once. */ -#undef AA_APPLE_UNIVERSAL_BUILD - /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD -/* Define to the number of bits in type 'ptrdiff_t'. */ -#undef BITSIZEOF_PTRDIFF_T - -/* Define to the number of bits in type 'sig_atomic_t'. */ -#undef BITSIZEOF_SIG_ATOMIC_T - -/* Define to the number of bits in type 'size_t'. */ -#undef BITSIZEOF_SIZE_T - -/* Define to the number of bits in type 'wchar_t'. */ -#undef BITSIZEOF_WCHAR_T +/* Directories from which to load auto-loaded scripts. */ +#undef AUTO_LOAD_DIR -/* Define to the number of bits in type 'wint_t'. */ -#undef BITSIZEOF_WINT_T +/* Directories safe to hold auto-loaded files. */ +#undef AUTO_LOAD_SAFE_PATH -/* Define to 1 if the compiler supports long long. */ -#undef CC_HAS_LONG_LONG +/* Directory of programs. */ +#undef BINDIR /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. @@ -75,12 +62,6 @@ /* Define to the default OS ABI for this configuration. */ #undef GDB_OSABI_DEFAULT -/* Define to 1 when the gnulib module memchr should be tested. */ -#undef GNULIB_TEST_MEMCHR - -/* Define to 1 when the gnulib module memmem should be tested. */ -#undef GNULIB_TEST_MEMMEM - /* Define to 1 if you have `alloca', as a function or macro. */ #undef HAVE_ALLOCA @@ -88,18 +69,12 @@ */ #undef HAVE_ALLOCA_H -/* Define to 1 if you have the header file. */ -#undef HAVE_BP_SYM_H - /* Define to 1 if you have the `btowc' function. */ #undef HAVE_BTOWC /* Define to 1 if you have the `canonicalize_file_name' function. */ #undef HAVE_CANONICALIZE_FILE_NAME -/* Define to 1 if you have the header file. */ -#undef HAVE_CTYPE_H - /* Define to 1 if you have the header file. */ #undef HAVE_CURSESX_H @@ -126,10 +101,6 @@ */ #undef HAVE_DECL_MALLOC -/* Define to 1 if you have the declaration of `memmem', and to 0 if you don't. - */ -#undef HAVE_DECL_MEMMEM - /* Define to 1 if you have the declaration of `ptrace', and to 0 if you don't. */ #undef HAVE_DECL_PTRACE @@ -191,9 +162,6 @@ /* Define to 1 if you have the `getuid' function. */ #undef HAVE_GETUID -/* Define to 1 if you have the header file. */ -#undef HAVE_GNU_LIBC_VERSION_H - /* Define if has gregset_t. */ #undef HAVE_GREGSET_T @@ -221,9 +189,15 @@ /* Define to 1 if you have the `libiconvlist' function. */ #undef HAVE_LIBICONVLIST +/* Define if you have the lzma library. */ +#undef HAVE_LIBLZMA + /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM +/* Define to 1 if you have the `mcheck' library (-lmcheck). */ +#undef HAVE_LIBMCHECK + /* Define if Python 2.4 is being used. */ #undef HAVE_LIBPYTHON2_4 @@ -236,12 +210,6 @@ /* Define if Python 2.7 is being used. */ #undef HAVE_LIBPYTHON2_7 -/* Define if libunwind library is being used. */ -#undef HAVE_LIBUNWIND - -/* Define to 1 if you have the header file. */ -#undef HAVE_LIBUNWIND_H - /* Define to 1 if you have the header file. */ #undef HAVE_LIBUNWIND_IA64_H @@ -251,14 +219,17 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINK_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_PERF_EVENT_H + /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if the compiler supports long double. */ #undef HAVE_LONG_DOUBLE -/* Define to 1 if the system has the type `long long int'. */ -#undef HAVE_LONG_LONG_INT +/* Define to 1 if you have the `lstat' function. */ +#undef HAVE_LSTAT /* Define if has lwpid_t. */ #undef HAVE_LWPID_T @@ -266,16 +237,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_MACHINE_REG_H -/* Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including - config.h and . */ -#undef HAVE_MAP_ANONYMOUS - -/* Define to 1 if you have the `memchr' function. */ -#undef HAVE_MEMCHR - -/* Define to 1 if you have the `memmem' function. */ -#undef HAVE_MEMMEM - /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H @@ -285,9 +246,6 @@ /* Define to 1 if you have the `monstartup' function. */ #undef HAVE_MONSTARTUP -/* Define to 1 if you have the `mprotect' function. */ -#undef HAVE_MPROTECT - /* Define to 1 if you have the header file. */ #undef HAVE_NCURSES_H @@ -318,6 +276,9 @@ /* Define to 1 if you have the `posix_madvise' function. */ #undef HAVE_POSIX_MADVISE +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + /* Define to 1 if you have the `pread64' function. */ #undef HAVE_PREAD64 @@ -375,92 +336,14 @@ /* Define if sys/ptrace.h defines the PT_GETXMMREGS request. */ #undef HAVE_PT_GETXMMREGS +/* Define to 1 if you have the `pwrite' function. */ +#undef HAVE_PWRITE + /* Define if Python interpreter is being linked in. */ #undef HAVE_PYTHON -/* Define to 1 if btowc is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_BTOWC - -/* Define to 1 if mbrlen is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_MBRLEN - -/* Define to 1 if mbrtowc is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_MBRTOWC - -/* Define to 1 if mbsinit is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_MBSINIT - -/* Define to 1 if mbsnrtowcs is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_MBSNRTOWCS - -/* Define to 1 if mbsrtowcs is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_MBSRTOWCS - -/* Define to 1 if memmem is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_MEMMEM - -/* Define to 1 if mempcpy is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_MEMPCPY - -/* Define to 1 if memrchr is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_MEMRCHR - -/* Define to 1 if rawmemchr is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_RAWMEMCHR - -/* Define to 1 if stpcpy is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STPCPY - -/* Define to 1 if stpncpy is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STPNCPY - -/* Define to 1 if strcasestr is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRCASESTR - -/* Define to 1 if strchrnul is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRCHRNUL - -/* Define to 1 if strdup is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRDUP - -/* Define to 1 if strncat is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRNCAT - -/* Define to 1 if strndup is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRNDUP - -/* Define to 1 if strnlen is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRNLEN - -/* Define to 1 if strpbrk is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRPBRK - -/* Define to 1 if strsep is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRSEP - -/* Define to 1 if strsignal is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRSIGNAL - -/* Define to 1 if strtok_r is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRTOK_R - -/* Define to 1 if strverscmp is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_STRVERSCMP - -/* Define to 1 if wcrtomb is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_WCRTOMB - -/* Define to 1 if wcsnrtombs is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_WCSNRTOMBS - -/* Define to 1 if wcsrtombs is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_WCSRTOMBS - -/* Define to 1 if wctob is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_WCTOB - -/* Define to 1 if wcwidth is declared even after undefining macros. */ -#undef HAVE_RAW_DECL_WCWIDTH +/* Define to 1 if you have the `readlink' function. */ +#undef HAVE_READLINK /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH @@ -495,15 +378,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H -/* Define to 1 if 'sig_atomic_t' is a signed integer type. */ -#undef HAVE_SIGNED_SIG_ATOMIC_T - -/* Define to 1 if 'wchar_t' is a signed integer type. */ -#undef HAVE_SIGNED_WCHAR_T - -/* Define to 1 if 'wint_t' is a signed integer type. */ -#undef HAVE_SIGNED_WINT_T - /* Define to 1 if you have the `sigprocmask' function. */ #undef HAVE_SIGPROCMASK @@ -570,12 +444,15 @@ /* Define to 1 if `struct thread' is a member of `td_pcb'. */ #undef HAVE_STRUCT_THREAD_TD_PCB +/* Define to 1 if `struct user_regs_struct' is a member of `fs_base'. */ +#undef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE + +/* Define to 1 if `struct user_regs_struct' is a member of `gs_base'. */ +#undef HAVE_STRUCT_USER_REGS_STRUCT_GS_BASE + /* Define to 1 if you have the `syscall' function. */ #undef HAVE_SYSCALL -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_BITYPES_H - /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DEBUGREG_H @@ -592,15 +469,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILIO_H -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_INTTYPES_H - /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_MMAN_H - /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H @@ -629,6 +500,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H @@ -638,6 +512,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_UN_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_USER_H @@ -659,9 +536,6 @@ /* Define if using Solaris thread debugging. */ #undef HAVE_THREAD_DB_LIB -/* Define to 1 if you have the header file. */ -#undef HAVE_TIME_H - /* Define if you support the tkill syscall. */ #undef HAVE_TKILL_SYSCALL @@ -671,9 +545,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H -/* Define to 1 if the system has the type `unsigned long long int'. */ -#undef HAVE_UNSIGNED_LONG_LONG_INT - /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK @@ -689,15 +560,6 @@ /* Define to 1 if you have the `wborder' function. */ #undef HAVE_WBORDER -/* Define to 1 if you have the header file. */ -#undef HAVE_WCHAR_H - -/* Define if you have the 'wchar_t' type. */ -#undef HAVE_WCHAR_T - -/* Define if you have the 'wint_t' type. */ -#undef HAVE_WINT_T - /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK @@ -735,9 +597,6 @@ moved. */ #undef JIT_READER_DIR_RELOCATABLE -/* Define to a substitute value for mmap()'s MAP_ANONYMOUS flag. */ -#undef MAP_ANONYMOUS - /* Define if you want to use new multi-fd /proc interface (replaces HAVE_MULTIPLE_PROC_FDS as well as other macros). */ #undef NEW_PROC_API @@ -791,10 +650,6 @@ /* Define as the return type of ptrace. */ #undef PTRACE_TYPE_RET -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'ptrdiff_t'. */ -#undef PTRDIFF_T_SUFFIX - /* Define if the python directory should be relocated when GDB is moved. */ #undef PYTHON_PATH_RELOCATABLE @@ -813,10 +668,6 @@ /* Define to 1 if the `setpgrp' function takes no argument. */ #undef SETPGRP_VOID -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'sig_atomic_t'. */ -#undef SIG_ATOMIC_T_SUFFIX - /* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG @@ -829,10 +680,6 @@ /* The size of `unsigned __int128', as computed by sizeof. */ #undef SIZEOF_UNSIGNED___INT128 -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'size_t'. */ -#undef SIZE_T_SUFFIX - /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. @@ -841,9 +688,6 @@ STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION -/* Define to 1 if the `S_IS*' macros in do not work properly. */ -#undef STAT_MACROS_BROKEN - /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS @@ -854,6 +698,12 @@ moved. */ #undef SYSTEM_GDBINIT_RELOCATABLE +/* search for usr/lib et al within DIR */ +#undef TARGET_SYSTEM_ROOT + +/* Define if the sysroot directory should be relocated when GDB is moved. */ +#undef TARGET_SYSTEM_ROOT_RELOCATABLE + /* Define if has the TD_NOTALLOC error code. */ #undef THREAD_DB_HAS_TD_NOTALLOC @@ -866,19 +716,33 @@ /* Define to 1 if the regex included in libiberty should be used. */ #undef USE_INCLUDED_REGEX +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + /* Define if we should use the Windows API, instead of the POSIX API. On Windows, we use the Windows API when building for MinGW, but the POSIX API when building for Cygwin. */ #undef USE_WIN32API -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'wchar_t'. */ -#undef WCHAR_T_SUFFIX - -/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type - 'wint_t'. */ -#undef WINT_T_SUFFIX - /* Define if --with-python provides a path, either directly or via python-config.py --exec-prefix. */ #undef WITH_PYTHON_PATH @@ -925,31 +789,6 @@ /* Define if has link_map32 (solaris sparc-64 target) */ #undef _SYSCALL32 -/* Define to 500 only on HP-UX. */ -#undef _XOPEN_SOURCE - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ -#endif - - /* Define to empty if `const' does not conform to ANSI C. */ #undef const @@ -959,45 +798,8 @@ #undef inline #endif -/* Work around a bug in Apple GCC 4.0.1 build 5465: In C99 mode, it supports - the ISO C 99 semantics of 'extern inline' (unlike the GNU C semantics of - earlier versions), but does not display it by setting __GNUC_STDC_INLINE__. - __APPLE__ && __MACH__ test for MacOS X. - __APPLE_CC__ tests for the Apple compiler and its version. - __STDC_VERSION__ tests for the C99 mode. */ -#if defined __APPLE__ && defined __MACH__ && __APPLE_CC__ >= 5465 && !defined __cplusplus && __STDC_VERSION__ >= 199901L && !defined __GNUC_STDC_INLINE__ -# define __GNUC_STDC_INLINE__ 1 -#endif - /* Define to `int' if does not define. */ #undef pid_t -/* Define to the equivalent of the C99 'restrict' keyword, or to - nothing if this is not supported. Do not define if restrict is - supported directly. */ -#undef restrict -/* Work around a bug in Sun C++: it does not support _Restrict or - __restrict__, even though the corresponding Sun C compiler ends up with - "#define restrict _Restrict" or "#define restrict __restrict__" in the - previous line. Perhaps some future version of Sun C++ will work with - restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ -#if defined __SUNPRO_CC && !defined __RESTRICT -# define _Restrict -# define __restrict__ -#endif - -/* Define as a marker that can be attached to declarations that might not - be used. This helps to reduce warnings, such as from - GCC -Wunused-parameter. */ -#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) -# define _GL_UNUSED __attribute__ ((__unused__)) -#else -# define _GL_UNUSED -#endif -/* The name _UNUSED_PARAMETER_ is an earlier spelling, although the name - is a misnomer outside of parameter lists. */ -#define _UNUSED_PARAMETER_ _GL_UNUSED - - /* Define as `fork' if `vfork' does not work. */ #undef vfork diff --git a/contrib/gdb-7/gdb/config/aarch64/linux.mh b/contrib/gdb-7/gdb/config/aarch64/linux.mh new file mode 100644 index 0000000000..2b2202e8cf --- /dev/null +++ b/contrib/gdb-7/gdb/config/aarch64/linux.mh @@ -0,0 +1,27 @@ +# Host: AArch64 based machine running GNU/Linux +# +# Copyright (C) 2013 Free Software Foundation, Inc. +# Contributed by ARM Ltd. +# +# 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 . + +NAT_FILE= config/nm-linux.h +NATDEPFILES= inf-ptrace.o fork-child.o aarch64-linux-nat.o \ + proc-service.o linux-thread-db.o linux-nat.o linux-fork.o \ + linux-procfs.o linux-ptrace.o linux-osdata.o +NAT_CDEPS = $(srcdir)/proc-service.list + +LOADLIBES= -ldl $(RDYNAMIC) diff --git a/contrib/gdb-7/gdb/config/i386/cygwin64.mh b/contrib/gdb-7/gdb/config/i386/cygwin64.mh new file mode 100644 index 0000000000..f5102c49a6 --- /dev/null +++ b/contrib/gdb-7/gdb/config/i386/cygwin64.mh @@ -0,0 +1,20 @@ +# Native config information for GDB on PowerPC systems running FreeBSD. +# +# Copyright (C) 2013 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 . */ + +NATDEPFILES= i386-nat.o windows-nat.o amd64-windows-nat.o diff --git a/contrib/gdb-7/gdb/config/tilegx/linux.mh b/contrib/gdb-7/gdb/config/tilegx/linux.mh new file mode 100644 index 0000000000..56ef694b1f --- /dev/null +++ b/contrib/gdb-7/gdb/config/tilegx/linux.mh @@ -0,0 +1,12 @@ +# Host: Tilera TILE-Gx running GNU/Linux. + +NAT_FILE= config/nm-linux.h +NATDEPFILES= inf-ptrace.o fork-child.o \ + tilegx-linux-nat.o \ + proc-service.o linux-thread-db.o \ + linux-nat.o linux-osdata.o linux-fork.o \ + linux-procfs.o linux-ptrace.o + +# The dynamically loaded libthread_db needs access to symbols in the +# gdb executable. +LOADLIBES = -ldl $(RDYNAMIC) diff --git a/contrib/gdb-7/gdb/configure.ac b/contrib/gdb-7/gdb/configure.ac index 2fc39ff954..e7ce71b873 100644 --- a/contrib/gdb-7/gdb/configure.ac +++ b/contrib/gdb-7/gdb/configure.ac @@ -1,5 +1,5 @@ dnl Autoconf configure script for GDB, the GNU debugger. -dnl Copyright (C) 1995-2012 Free Software Foundation, Inc. +dnl Copyright (C) 1995-2013 Free Software Foundation, Inc. dnl dnl This file is part of GDB. dnl @@ -23,14 +23,19 @@ AC_INIT(main.c) AC_CONFIG_HEADER(config.h:config.in) AM_MAINTAINER_MODE +# Provide more thorough testing by -lmcheck. +# Set it to 'true' for development snapshots, 'false' for releases or +# pre-releases. +development=false + AC_PROG_CC AC_USE_SYSTEM_EXTENSIONS -gl_EARLY ACX_LARGEFILE AM_PROG_CC_STDC AC_CONFIG_AUX_DIR(..) AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM # Dependency checking. ZW_CREATE_DEPDIR @@ -47,6 +52,12 @@ esac AM_CONDITIONAL(GMAKE, test "$MAKE_IS_GNU" = yes) AC_PROG_MAKE_SET +# Configure gnulib. We need to build gnulib under some other +# directory not "gnulib", to avoid the problem of both GDB and +# GDBserver wanting to build it in the same directory, when building +# in the source dir. +ACX_CONFIGURE_DIR(["gnulib"], ["build-gnulib"]) + dnl List of object files and targets accumulated by configure. CONFIG_OBS= @@ -72,12 +83,12 @@ if test x"$USE_NLS" = xyes; then CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-po" fi -gl_INIT +GNULIB=build-gnulib/import # For Makefile dependencies. GNULIB_STDINT_H= if test x"$STDINT_H" != x; then - GNULIB_STDINT_H=gnulib/$STDINT_H + GNULIB_STDINT_H=$GNULIB/$STDINT_H fi AC_SUBST(GNULIB_STDINT_H) @@ -105,14 +116,18 @@ if test x"$gdb_cv_have_makeinfo_click" = xyes; then fi AC_SUBST(MAKEINFO_EXTRA_FLAGS) -# GDB does not use automake, but gnulib does. This line lets us -# generate its Makefile.in. -AM_INIT_AUTOMAKE(gdb, UNUSED-VERSION, [no-define]) - GDB_AC_WITH_DIR(DEBUGDIR, separate-debug-dir, [look for global separate debug info in this path @<:@LIBDIR/debug@:>@], [${libdir}/debug]) +# We can't pass paths as command line arguments. +# Mingw32 tries to be clever and will convert the paths for us. +# For example -DBINDIR="/usr/local/bin" passed on the command line may get +# converted to -DBINDIR="E:/msys/mingw32/msys/1.0/local/bin". +# This breaks GDB's relocatable path conversions since paths passed in +# config.h would not get so translated, the path prefixes no longer match. +AC_DEFINE_DIR(BINDIR, bindir, [Directory of programs.]) + # GDB's datadir relocation GDB_AC_WITH_DIR(GDB_DATADIR, gdb-datadir, @@ -126,6 +141,31 @@ AS_HELP_STRING([--with-relocated-sources=PATH], [automatically relocate this pat [Relocated directory for source files. ]) ]) +AC_MSG_CHECKING([for default auto-load directory]) +AC_ARG_WITH(auto-load-dir, +AS_HELP_STRING([--with-auto-load-dir=PATH], + [directories from which to load auto-loaded scripts @<:@$debugdir:$datadir/auto-load@:>@]),, + [with_auto_load_dir='$debugdir:$datadir/auto-load']) +escape_dir=`echo $with_auto_load_dir | sed 's/[[$]]\(datadir\|debugdir\)\>/\\\\\\\\\\\\&/g'` +AC_DEFINE_DIR(AUTO_LOAD_DIR, escape_dir, + [Directories from which to load auto-loaded scripts.]) +AC_MSG_RESULT([$with_auto_load_dir]) + +AC_MSG_CHECKING([for default auto-load safe-path]) +AC_ARG_WITH(auto-load-safe-path, +AS_HELP_STRING([--with-auto-load-safe-path=PATH], + [directories safe to hold auto-loaded files @<:@--with-auto-load-dir@:>@]) +AS_HELP_STRING([--without-auto-load-safe-path], + [do not restrict auto-loaded files locations]), + [if test "$with_auto_load_safe_path" = "no"; then + with_auto_load_safe_path="/" + fi], +[with_auto_load_safe_path="$with_auto_load_dir"]) +escape_dir=`echo $with_auto_load_safe_path | sed 's/[[$]]\(datadir\|debugdir\)\>/\\\\\\\\\\\\&/g'` +AC_DEFINE_DIR(AUTO_LOAD_SAFE_PATH, escape_dir, + [Directories safe to hold auto-loaded files.]) +AC_MSG_RESULT([$with_auto_load_safe_path]) + AC_CONFIG_SUBDIRS(testsuite) # Check whether to support alternative target configurations @@ -320,26 +360,44 @@ case $host_os in enable_gdbtk=no ;; esac -# Libunwind support. -AC_ARG_WITH(libunwind, -AS_HELP_STRING([--with-libunwind], [use libunwind frame unwinding support]), -[case "${withval}" in - yes) enable_libunwind=yes ;; - no) enable_libunwind=no ;; - *) AC_MSG_ERROR(bad value ${withval} for GDB with-libunwind option) ;; -esac],[ - AC_CHECK_HEADERS(libunwind.h libunwind-ia64.h) - if test x"$ac_cv_header_libunwind_h" = xyes -a x"$ac_cv_header_libunwind_ia64_h" = xyes; then - enable_libunwind=yes; +# Libunwind support for ia64. + +AC_ARG_WITH(libunwind-ia64, +AS_HELP_STRING([--with-libunwind-ia64], + [use libunwind frame unwinding for ia64 targets]),, + [with_libunwind_ia64=auto]) + +# Backward compatibility option. +if test "${with_libunwind+set}" = set; then + if test x"$with_libunwind_ia64" != xauto; then + AC_MSG_ERROR( + [option --with-libunwind is deprecated, use --with-libunwind-ia64]) fi -]) - -if test x"$enable_libunwind" = xyes; then - AC_CHECK_HEADERS(libunwind.h libunwind-ia64.h) - AC_DEFINE(HAVE_LIBUNWIND, 1, [Define if libunwind library is being used.]) - CONFIG_OBS="$CONFIG_OBS libunwind-frame.o" - CONFIG_DEPS="$CONFIG_DEPS libunwind-frame.o" - CONFIG_SRCS="$CONFIG_SRCS libunwind-frame.c" + AC_MSG_WARN([option --with-libunwind is deprecated, use --with-libunwind-ia64]) + with_libunwind_ia64="$with_libunwind" +fi + +case "$with_libunwind_ia64" in + yes | no) + ;; + auto) + AC_CHECK_HEADERS(libunwind-ia64.h) + with_libunwind_ia64=$ac_cv_header_libunwind_ia64_h + ;; + *) + AC_MSG_ERROR( + [bad value $with_libunwind_ia64 for GDB --with-libunwind-ia64 option]) + ;; +esac + +if test x"$with_libunwind_ia64" = xyes; then + AC_CHECK_HEADERS(libunwind-ia64.h) + if test x"$ac_cv_header_libunwind_ia64_h" != xyes; then + AC_MSG_ERROR([GDB option --with-libunwind-ia64 requires libunwind-ia64.h]) + fi + CONFIG_OBS="$CONFIG_OBS ia64-libunwind-tdep.o" + CONFIG_DEPS="$CONFIG_DEPS ia64-libunwind-tdep.o" + CONFIG_SRCS="$CONFIG_SRCS ia64-libunwind-tdep.c" fi opt_curses=no @@ -531,10 +589,6 @@ if test x"$enable_tui" != xno; then CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_TUI_DEPS)" CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_TUI_SRCS)" ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_TUI_CFLAGS)" - CONFIG_ALL="${CONFIG_ALL} all-tui" - CONFIG_CLEAN="${CONFIG_CLEAN} clean-tui" - CONFIG_INSTALL="${CONFIG_INSTALL} install-tui" - CONFIG_UNINSTALL="${CONFIG_UNINSTALL} uninstall-tui" else if test x"$enable_tui" = xyes; then AC_MSG_ERROR([no enhanced curses library found; disable TUI]) @@ -718,7 +772,7 @@ if test "${with_python}" = no; then have_libpython=no else case "${with_python}" in - /*) + [[\\/]]* | ?:[[\\/]]*) if test -d ${with_python}; then # Assume the python binary is ${with_python}/bin/python. python_prog="${with_python}/bin/python" @@ -935,12 +989,43 @@ if test "${have_libpython}" != no; then # unilaterally defined, and that in turn causes _SGIAPI to evaluate # to false. So, we work around this issue by defining siginfo ourself # though the command-line. + # + # On x64 Windows, Python's include headers, and pyconfig.h in + # particular, rely on MS_WIN64 macro to detect that it's a 64bit + # version of Windows. Unfortunately, MS_WIN64 is only defined if + # _MSC_VER, a Microsoft-specific macro, is defined. So, when + # building on x64 Windows with GCC, we define MS_WIN64 ourselves. + # The issue was reported to the Python community, but still isn't + # solved as of 2012-10-02 (http://bugs.python.org/issue4709). + case "$gdb_host" in irix*) if test "${GCC}" = yes; then CPPFLAGS="$CPPFLAGS -Dsiginfo=__siginfo" fi ;; + mingw64) + if test "${GCC}" = yes; then + CPPFLAGS="$CPPFLAGS -DMS_WIN64" + fi + ;; esac + + # Note that "python -m threading" cannot be used to check for + # threading support due to a bug in Python 2.7.3 + # (http://bugs.python.org/issue15567). + AC_MSG_CHECKING(whether python supports threads) + saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${PYTHON_CPPFLAGS}" + # Note that the test is reversed so that python_has_threads=yes on + # unexpected failures. + AC_PREPROC_IFELSE(AC_LANG_SOURCE([[ +#include +#ifdef WITH_THREAD +# error +#endif + ]]), [python_has_threads=no], [python_has_threads=yes]) + AC_MSG_RESULT(${python_has_threads}) + CPPFLAGS="${saved_CPPFLAGS}" else # Even if Python support is not compiled in, we need to have these files # included. @@ -952,25 +1037,52 @@ AC_SUBST(PYTHON_CFLAGS) AC_SUBST(PYTHON_CPPFLAGS) AC_SUBST(PYTHON_LIBS) +# Provide a --enable-libmcheck/--disable-libmcheck set of options +# allowing a user to enable this option even when building releases, +# or to disable it when building a snapshot. +AC_ARG_ENABLE(libmcheck, + AS_HELP_STRING([--enable-libmcheck], + [Try building GDB with -lmcheck if available]), + [case "${enableval}" in + yes | y) ENABLE_LIBMCHECK="yes" ;; + no | n) ENABLE_LIBMCHECK="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-libmcheck) ;; + esac]) + +# Enable -lmcheck by default (it provides cheap-enough memory mangling), +# but turn it off if Python is enabled with threads, since -lmcheck is +# not thread safe (http://sourceware.org/bugzilla/show_bug.cgi?id=9939), +# and for releases. +if test -z "${ENABLE_LIBMCHECK}" \ + -a \( "${have_libpython}" = "no" \ + -o "${python_has_threads}" = "no" \) \ + && $development; then + ENABLE_LIBMCHECK=yes +fi + +if test "$ENABLE_LIBMCHECK" = "yes" ; then + if test "${have_libpython}" != "no" -a "${python_has_threads}" = "yes" ; then + AC_MSG_WARN(--enable-libmcheck may lead to spurious crashes if threads are used in python) + fi + AC_CHECK_LIB(mcheck, main) +fi + # ------------------------- # # Checks for header files. # # ------------------------- # AC_HEADER_DIRENT -AC_HEADER_STAT AC_HEADER_STDC # 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? AC_CHECK_HEADERS([nlist.h machine/reg.h poll.h sys/poll.h proc_service.h \ - thread_db.h gnu/libc-version.h signal.h stddef.h \ + thread_db.h signal.h stddef.h \ stdlib.h string.h memory.h strings.h sys/fault.h \ sys/file.h sys/filio.h sys/ioctl.h sys/param.h \ sys/resource.h sys/procfs.h sys/ptrace.h ptrace.h \ sys/reg.h sys/debugreg.h sys/select.h sys/syscall.h \ sys/types.h sys/wait.h wait.h termios.h termio.h \ - sgtty.h unistd.h elf_hp.h ctype.h time.h locale.h \ - dlfcn.h]) + sgtty.h unistd.h elf_hp.h locale.h \ + dlfcn.h sys/socket.h sys/un.h linux/perf_event.h]) AC_CHECK_HEADERS(link.h, [], [], [#if HAVE_SYS_TYPES_H # include @@ -1047,11 +1159,12 @@ AC_C_BIGENDIAN AC_FUNC_ALLOCA AC_FUNC_MMAP AC_FUNC_VFORK -AC_CHECK_FUNCS([canonicalize_file_name realpath getrusage getuid \ - getgid pipe poll pread64 resize_term sbrk setpgid setpgrp setsid \ +AC_CHECK_FUNCS([canonicalize_file_name realpath getrusage getuid getgid \ + pipe poll pread pread64 pwrite readlink resize_term \ + sbrk setpgid setpgrp setsid \ sigaction sigprocmask sigsetmask socketpair syscall \ ttrace wborder wresize setlocale iconvlist libiconvlist btowc \ - setrlimit getrlimit posix_madvise waitpid]) + setrlimit getrlimit posix_madvise waitpid lstat]) AM_LANGINFO_CODESET # Check the return and argument types of ptrace. No canned test for @@ -1214,6 +1327,12 @@ fi AC_CHECK_MEMBERS([struct reg.r_fs, struct reg.r_gs], [], [], [#include ]) +# See if supports the %fs_base and %gs_bas amd64 segment registers. +# Older amd64 Linux's don't have the fs_base and gs_base members of +# `struct user_regs_struct'. +AC_CHECK_MEMBERS([struct user_regs_struct.fs_base, struct user_regs_struct.gs_base], + [], [], [#include ]) + # See if provides the PTRACE_GETREGS request. AC_MSG_CHECKING(for PTRACE_GETREGS) AC_CACHE_VAL(gdb_cv_have_ptrace_getregs, @@ -1268,11 +1387,11 @@ if test $gdb_cv_have_pt_getxmmregs = yes; then [Define if sys/ptrace.h defines the PT_GETXMMREGS request.]) fi -# Detect which type of /proc is in use, such as for Unixware or Solaris. +# Detect which type of /proc is in use, such as for Solaris. if test "${target}" = "${host}"; then case "${host}" in - *-*-unixware* | *-*-sysv4.2* | *-*-sysv5* | *-*-interix* ) + *-*-sysv4.2* | *-*-sysv5* | *-*-interix* ) AC_DEFINE(NEW_PROC_API, 1, [Define if you want to use new multi-fd /proc interface (replaces HAVE_MULTIPLE_PROC_FDS as well as other macros).]) @@ -1437,9 +1556,9 @@ AC_CACHE_CHECK([for long long support in compiler], gdb_cv_c_long_long, [[switch (foo & 2) { case 0: return 1; }]])], gdb_cv_c_long_long=yes, gdb_cv_c_long_long=no)]) -if test $gdb_cv_c_long_long = yes; then - AC_DEFINE(CC_HAS_LONG_LONG, 1, - [Define to 1 if the compiler supports long long.]) +if test $gdb_cv_c_long_long != yes; then + # libdecnumber requires long long. + AC_MSG_ERROR([Compiler must support long long for GDB.]) fi # Check if the compiler and runtime support printing long longs. @@ -1568,6 +1687,8 @@ if test "${gdb_native}" = yes; then # Problem does not happen for the recommended libpythonX.Y.so linkage. old_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PYTHON_CFLAGS" + old_LIBS="$LIBS" + LIBS="$LIBS $PYTHON_LIBS" AC_RUN_IFELSE( AC_LANG_PROGRAM( [#include "]${have_libpython}[/Python.h"], @@ -1577,6 +1698,7 @@ if test "${gdb_native}" = yes; then Py_Finalize (); return err == 0 ? 0 : 1;]), [dynamic_list=true], [], [true]) + LIBS="$old_LIBS" CFLAGS="$old_CFLAGS" fi LDFLAGS="$old_LDFLAGS" @@ -1647,7 +1769,7 @@ if test ${build} = ${host} -a ${host} = ${target} ; then if test $gdb_cv_have_aix_thread_debug = yes; then CONFIG_SRCS="${CONFIG_SRCS} aix-thread.c" CONFIG_OBS="${CONFIG_OBS} aix-thread.o" - CONFIG_LDFLAGS="${CONFIG_LDFLAGS} -lpthdebug" + LIBS="$LIBS -lpthdebug" # Older versions of AIX do not provide the declaration for # the getthrds function (it appears that it was introduced @@ -1745,42 +1867,20 @@ fi dnl Handle optional features that can be enabled. -target_sysroot_reloc=0 +# Support for --with-sysroot is a copy of GDB_AC_WITH_DIR, +# except that the argument to --with-sysroot is optional. +# --with-sysroot (or --with-sysroot=yes) sets the default sysroot path. +if test "x$with_sysroot" = xyes; then + with_sysroot="${exec_prefix}/${target_alias}/sys-root" +fi AC_ARG_WITH(sysroot, -AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [search for usr/lib et al within DIR]), -[ - case ${with_sysroot} in - yes) TARGET_SYSTEM_ROOT='${exec_prefix}/${target_alias}/sys-root' ;; - *) TARGET_SYSTEM_ROOT=$with_sysroot ;; - esac - - TARGET_SYSTEM_ROOT_DEFINE='-DTARGET_SYSTEM_ROOT=\"$(TARGET_SYSTEM_ROOT)\"' - - if test "x$prefix" = xNONE; then - test_prefix=/usr/local - else - test_prefix=$prefix - fi - if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then - test_exec_prefix=$test_prefix - else - test_exec_prefix=$exec_prefix - fi - case ${TARGET_SYSTEM_ROOT} in - "${test_prefix}"|"${test_prefix}/"*|\ - "${test_exec_prefix}"|"${test_exec_prefix}/"*|\ - '${prefix}'|'${prefix}/'*|\ - '${exec_prefix}'|'${exec_prefix}/'*) - target_sysroot_reloc=1 - ;; - esac -], [ - TARGET_SYSTEM_ROOT= - TARGET_SYSTEM_ROOT_DEFINE='-DTARGET_SYSTEM_ROOT=\"\"' -]) -TARGET_SYSTEM_ROOT_DEFINE="$TARGET_SYSTEM_ROOT_DEFINE -DTARGET_SYSTEM_ROOT_RELOCATABLE=$target_sysroot_reloc" + AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], + [search for usr/lib et al within DIR]), + [TARGET_SYSTEM_ROOT=$withval], [TARGET_SYSTEM_ROOT=]) +AC_DEFINE_DIR(TARGET_SYSTEM_ROOT, TARGET_SYSTEM_ROOT, + [search for usr/lib et al within DIR]) AC_SUBST(TARGET_SYSTEM_ROOT) -AC_SUBST(TARGET_SYSTEM_ROOT_DEFINE) +GDB_AC_DEFINE_RELOCATABLE(TARGET_SYSTEM_ROOT, sysroot, ${ac_define_dir}) GDB_AC_WITH_DIR(SYSTEM_GDBINIT, system-gdbinit, [automatically load a system-wide gdbinit file], @@ -1794,6 +1894,11 @@ AC_ARG_ENABLE(werror, *) AC_MSG_ERROR(bad value ${enableval} for --enable-werror) ;; esac]) +# Enable -Werror by default when using gcc. Turn it off for releases. +if test "${GCC}" = yes -a -z "${ERROR_ON_WARNING}" && $development; then + ERROR_ON_WARNING=yes +fi + WERROR_CFLAGS="" if test "${ERROR_ON_WARNING}" = yes ; then WERROR_CFLAGS="-Werror" @@ -1807,7 +1912,8 @@ fi build_warnings="-Wall -Wdeclaration-after-statement -Wpointer-arith \ -Wformat-nonliteral -Wno-pointer-sign \ -Wno-unused -Wunused-value -Wunused-function \ --Wno-switch -Wno-char-subscripts" +-Wno-switch -Wno-char-subscripts -Wmissing-prototypes \ +-Wdeclaration-after-statement -Wempty-body" # Enable -Wno-format by default when using gcc on mingw since many # GCC versions complain about %I64. @@ -1905,41 +2011,56 @@ esac AC_SUBST(WIN32LIBS) # Add ELF support to GDB, but only if BFD includes ELF support. -OLD_CFLAGS=$CFLAGS -OLD_LDFLAGS=$LDFLAGS -OLD_LIBS=$LIBS -CFLAGS="$CFLAGS -I${srcdir}/../include -I../bfd -I${srcdir}/../bfd" -LDFLAGS="$LDFLAGS -L../bfd -L../libiberty" -intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'` -# -ldl is provided by bfd/Makfile.am (LIBDL) . -if test "$plugins" = "yes"; then - LIBS="-ldl $LIBS" -fi -LIBS="-lbfd -liberty $intl $LIBS" -AC_CACHE_CHECK([for ELF support in BFD], gdb_cv_var_elf, -[AC_TRY_LINK( -[#include -#include "bfd.h" -#include "elf-bfd.h" -], -[bfd *abfd = NULL; bfd_get_elf_phdr_upper_bound (abfd); ], -gdb_cv_var_elf=yes, gdb_cv_var_elf=no)]) +GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf, + [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h) if test $gdb_cv_var_elf = yes; then - CONFIG_OBS="$CONFIG_OBS elfread.o" + CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o" AC_DEFINE(HAVE_ELF, 1, [Define if ELF support should be included.]) # -ldl is provided by bfd/Makfile.am (LIBDL) . if test "$plugins" = "yes"; then - OLD_LIBS="-ldl $OLD_LIBS" + LIBS="-ldl $LIBS" fi fi -CFLAGS=$OLD_CFLAGS -LDFLAGS=$OLD_LDFLAGS -LIBS=$OLD_LIBS + +# Add macho support to GDB, but only if BFD includes it. +GDB_AC_CHECK_BFD([for Mach-O support in BFD], gdb_cv_var_macho, + [bfd_mach_o_lookup_command (NULL, 0, NULL)], mach-o.h) +if test $gdb_cv_var_macho = yes; then + CONFIG_OBS="$CONFIG_OBS machoread.o" +fi + +# Add SOM support to GDB, but only if BFD includes it. +GDB_AC_CHECK_BFD([for SOM support in BFD], gdb_cv_var_som, + [bfd_som_attach_aux_hdr (NULL, 0, NULL)], som.h) +if test $gdb_cv_var_som = yes; then + CONFIG_OBS="$CONFIG_OBS somread.o" +fi # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" +# If building on ELF, look for lzma support for embedded compressed debug info. +if test $gdb_cv_var_elf = yes; then + AC_ARG_WITH(lzma, + AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]), + [], [with_lzma=auto]) + AC_MSG_CHECKING([whether to use lzma]) + AC_MSG_RESULT([$with_lzma]) + + if test "${with_lzma}" != no; then + AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"], + [lzma_index_iter iter; + lzma_index_iter_init (&iter, 0); + lzma_mf_is_supported (LZMA_MF_HC3);]) + if test "$HAVE_LIBLZMA" != yes; then + if test "$with_lzma" = yes; then + AC_MSG_ERROR([missing liblzma for --with-lzma]) + fi + fi + fi +fi + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" AC_SUBST(LIBGUI) @@ -2221,7 +2342,7 @@ 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.]) -AC_OUTPUT(Makefile .gdbinit:gdbinit.in doc/Makefile gnulib/Makefile data-directory/Makefile, +AC_OUTPUT(Makefile gdb-gdb.gdb doc/Makefile data-directory/Makefile, [ case x$CONFIG_HEADERS in xconfig.h:config.in) diff --git a/contrib/gdb-7/gdb/configure.host b/contrib/gdb-7/gdb/configure.host index 531f4587c0..85f4491b8f 100644 --- a/contrib/gdb-7/gdb/configure.host +++ b/contrib/gdb-7/gdb/configure.host @@ -39,6 +39,7 @@ esac case "${host_cpu}" in +aarch64*) gdb_host_cpu=aarch64 ;; alpha*) gdb_host_cpu=alpha ;; arm*) gdb_host_cpu=arm ;; hppa*) gdb_host_cpu=pa ;; @@ -50,6 +51,7 @@ powerpc* | rs6000) gdb_host_cpu=powerpc ;; sparcv9 | sparc64) gdb_host_cpu=sparc ;; s390*) gdb_host_cpu=s390 ;; sh*) gdb_host_cpu=sh ;; +tilegx*) gdb_host_cpu=tilegx ;; x86_64*) gdb_host_cpu=i386 ;; m32r*) gdb_host_cpu=m32r ;; xtensa*) gdb_host_cpu=xtensa ;; @@ -63,6 +65,8 @@ case "${host}" in *-*-darwin*) gdb_host=darwin ;; +aarch64*-*-linux*) gdb_host=linux ;; + alpha*-*-osf[3456789]*) gdb_host=alpha-osf3 ;; alpha*-*-linux*) gdb_host=alpha-linux ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) @@ -124,6 +128,7 @@ mips64*-*-openbsd*) gdb_host=obsd64 ;; powerpc-*-aix* | rs6000-*-*) gdb_host=aix ;; +powerpc*-*-freebsd*) gdb_host=fbsd ;; powerpc-*-linux*) gdb_host=linux ;; powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu) gdb_host=nbsd ;; @@ -159,6 +164,8 @@ sparc-*-solaris2* | sparcv9-*-solaris2* | sparc64-*-solaris2*) gdb_host=sol2 ;; +tilegx-*-linux*) gdb_host=linux ;; + vax-*-bsd*) gdb_host=vax ;; vax-*-netbsdelf* | vax-*-knetbsd*-gnu) gdb_host=nbsdelf ;; @@ -175,6 +182,7 @@ x86_64-*-openbsd*) gdb_host=obsd64 ;; x86_64-*-mingw*) gdb_host=mingw64 gdb_host_obs=mingw-hdep.o ;; +x86_64-*-cygwin*) gdb_host=cygwin64 ;; m32r*-*-linux*) gdb_host=linux ;; xtensa*-*-linux*) gdb_host=linux ;; diff --git a/contrib/gdb-7/gdb/configure.tgt b/contrib/gdb-7/gdb/configure.tgt index 137debae6f..720d3d3ca1 100644 --- a/contrib/gdb-7/gdb/configure.tgt +++ b/contrib/gdb-7/gdb/configure.tgt @@ -31,6 +31,18 @@ esac # map target info into gdb names. case "${targ}" in +aarch64*-*-elf) + # Target: AArch64 embedded system + gdb_target_obs="aarch64-tdep.o aarch64-newlib-tdep.o" + ;; + +aarch64*-*-linux*) + # Target: AArch64 linux + gdb_target_obs="aarch64-tdep.o aarch64-linux-tdep.o \ + glibc-tdep.o linux-tdep.o solib-svr4.o \ + symfile-mem.o" + build_gdbserver=yes + ;; alpha*-*-osf*) # Target: Little-endian Alpha running OSF/1 @@ -39,24 +51,23 @@ alpha*-*-osf*) alpha*-*-linux*) # Target: Little-endian Alpha running Linux gdb_target_obs="alpha-tdep.o alpha-mdebug-tdep.o alpha-linux-tdep.o \ - linux-tdep.o solib.o solib-svr4.o" + linux-tdep.o solib-svr4.o" ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) # Target: FreeBSD/alpha gdb_target_obs="alpha-tdep.o alpha-mdebug-tdep.o alphabsd-tdep.o \ - alphafbsd-tdep.o corelow.o solib.o solib-svr4.o" + alphafbsd-tdep.o solib-svr4.o" ;; alpha*-*-netbsd* | alpha*-*-knetbsd*-gnu) # Target: NetBSD/alpha gdb_target_obs="alpha-tdep.o alpha-mdebug-tdep.o alphabsd-tdep.o \ - alphanbsd-tdep.o nbsd-tdep.o corelow.o solib.o \ - solib-svr4.o" + alphanbsd-tdep.o nbsd-tdep.o solib-svr4.o" ;; alpha*-*-openbsd*) # Target: OpenBSD/alpha gdb_target_obs="alpha-tdep.o alpha-mdebug-tdep.o alphabsd-tdep.o \ alphanbsd-tdep.o alphaobsd-tdep.o nbsd-tdep.o \ - obsd-tdep.o corelow.o solib.o solib-svr4.o" + obsd-tdep.o solib-svr4.o" ;; alpha*-*-*) # Target: Alpha @@ -66,33 +77,32 @@ alpha*-*-*) am33_2.0*-*-linux*) # Target: Matsushita mn10300 (AM33) running Linux gdb_target_obs="mn10300-tdep.o mn10300-linux-tdep.o linux-tdep.o \ - corelow.o solib.o solib-svr4.o" + solib-svr4.o" ;; arm*-wince-pe | arm*-*-mingw32ce*) # Target: ARM based machine running Windows CE (win32) - gdb_target_obs="arm-tdep.o arm-wince-tdep.o corelow.o \ - solib.o solib-target.o" + gdb_target_obs="arm-tdep.o arm-wince-tdep.o" build_gdbserver=yes ;; arm*-*-linux*) # Target: ARM based machine running GNU/Linux gdb_target_obs="arm-tdep.o arm-linux-tdep.o glibc-tdep.o \ - solib.o solib-svr4.o symfile-mem.o corelow.o linux-tdep.o" + solib-svr4.o symfile-mem.o linux-tdep.o" build_gdbserver=yes ;; arm*-*-netbsd* | arm*-*-knetbsd*-gnu) # Target: NetBSD/arm - gdb_target_obs="arm-tdep.o armnbsd-tdep.o solib.o solib-svr4.o" + gdb_target_obs="arm-tdep.o armnbsd-tdep.o solib-svr4.o" ;; arm*-*-openbsd*) # Target: OpenBSD/arm gdb_target_obs="arm-tdep.o armbsd-tdep.o armobsd-tdep.o obsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + solib-svr4.o" ;; arm*-*-symbianelf*) # Target: SymbianOS/arm - gdb_target_obs="arm-tdep.o solib-target.o arm-symbian-tdep.o" + gdb_target_obs="arm-tdep.o arm-symbian-tdep.o" ;; arm*-*-*) # Target: ARM embedded system @@ -120,17 +130,16 @@ bfin-*-*) cris*) # Target: CRIS - gdb_target_obs="cris-tdep.o corelow.o solib.o solib-svr4.o" + gdb_target_obs="cris-tdep.o solib-svr4.o" ;; frv-*-*) # Target: Fujitsu FRV processor - gdb_target_obs="frv-tdep.o frv-linux-tdep.o linux-tdep.o \ - solib.o solib-frv.o corelow.o" + gdb_target_obs="frv-tdep.o frv-linux-tdep.o linux-tdep.o solib-frv.o" gdb_sim=../sim/frv/libsim.a ;; -moxie-*-elf) +moxie-*-elf | moxie-*-rtems*) gdb_target_obs="moxie-tdep.o" gdb_sim=../sim/moxie/libsim.a ;; @@ -143,23 +152,20 @@ h8300-*-*) hppa*-*-hpux*) # Target: HP PA-RISC running hpux - gdb_target_obs="hppa-tdep.o hppa-hpux-tdep.o corelow.o \ - solib.o solib-som.o solib-pa64.o" + gdb_target_obs="hppa-tdep.o hppa-hpux-tdep.o solib-som.o solib-pa64.o" ;; hppa*-*-linux*) # Target: HP PA-RISC running Linux gdb_target_obs="hppa-tdep.o hppa-linux-tdep.o glibc-tdep.o \ - linux-tdep.o solib.o solib-svr4.o symfile-mem.o" + linux-tdep.o solib-svr4.o symfile-mem.o" ;; hppa*-*-netbsd*) # Target: NetBSD/hppa - gdb_target_obs="hppa-tdep.o hppabsd-tdep.o hppanbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + gdb_target_obs="hppa-tdep.o hppabsd-tdep.o hppanbsd-tdep.o solib-svr4.o" ;; hppa*-*-openbsd*) # Target: OpenBSD/hppa - gdb_target_obs="hppa-tdep.o hppabsd-tdep.o hppaobsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + gdb_target_obs="hppa-tdep.o hppabsd-tdep.o hppaobsd-tdep.o solib-svr4.o" ;; hppa*-*-*) # Target: HP PA-RISC @@ -169,7 +175,7 @@ hppa*-*-*) i[34567]86-*-darwin*) # Target: Darwin/i386 gdb_target_obs="i386-tdep.o i387-tdep.o \ - i386-darwin-tdep.o solib.o solib-darwin.o" + i386-darwin-tdep.o solib-darwin.o" if test "x$enable_64_bit_bfd" = "xyes"; then # Target: GNU/Linux x86-64 gdb_target_obs="amd64-tdep.o amd64-darwin-tdep.o ${gdb_target_obs}" @@ -177,46 +183,43 @@ i[34567]86-*-darwin*) ;; i[34567]86-*-dicos*) # Target: DICOS/i386 - gdb_target_obs="i386-tdep.o i387-tdep.o \ - dicos-tdep.o i386-dicos-tdep.o \ - corelow.o solib.o solib-target.o" + gdb_target_obs="i386-tdep.o i387-tdep.o dicos-tdep.o i386-dicos-tdep.o" ;; i[34567]86-*-freebsd* | i[34567]86-*-kfreebsd*-gnu) # Target: FreeBSD/i386 gdb_target_obs="i386-tdep.o i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \ - bsd-uthread.o corelow.o solib.o solib-svr4.o" + bsd-uthread.o solib-svr4.o" ;; i[34567]86-*-netbsd* | i[34567]86-*-knetbsd*-gnu) # Target: NetBSD/i386 gdb_target_obs="i386-tdep.o i387-tdep.o i386bsd-tdep.o i386nbsd-tdep.o \ - nbsd-tdep.o corelow.o solib.o solib-svr4.o" + nbsd-tdep.o solib-svr4.o" ;; i[34567]86-*-openbsd*) # Target: OpenBSD/i386 gdb_target_obs="i386-tdep.o i387-tdep.o i386bsd-tdep.o i386obsd-tdep.o \ - bsd-uthread.o corelow.o solib.o solib-svr4.o" + bsd-uthread.o solib-svr4.o" ;; i[34567]86-*-nto*) # Target: Intel 386 running qnx6. - gdb_target_obs="i386-tdep.o i387-tdep.o corelow.o solib.o solib-svr4.o \ + gdb_target_obs="i386-tdep.o i387-tdep.o solib-svr4.o \ i386-nto-tdep.o nto-tdep.o" build_gdbserver=yes ;; i[34567]86-*-solaris2.1[0-9]* | x86_64-*-solaris2.1[0-9]*) # Target: Solaris x86_64 gdb_target_obs="i386-tdep.o i387-tdep.o amd64-tdep.o amd64-sol2-tdep.o \ - i386-sol2-tdep.o sol2-tdep.o \ - corelow.o solib.o solib-svr4.o" + i386-sol2-tdep.o sol2-tdep.o solib-svr4.o" ;; i[34567]86-*-solaris*) # Target: Solaris x86 gdb_target_obs="i386-tdep.o i387-tdep.o i386-sol2-tdep.o sol2-tdep.o \ - corelow.o solib.o solib-svr4.o" + solib-svr4.o" ;; i[34567]86-*-linux*) # Target: Intel 386 running GNU/Linux gdb_target_obs="i386-tdep.o i386-linux-tdep.o glibc-tdep.o i387-tdep.o \ - solib.o solib-svr4.o symfile-mem.o corelow.o \ + solib-svr4.o symfile-mem.o \ linux-tdep.o linux-record.o" if test "x$enable_64_bit_bfd" = "xyes"; then # Target: GNU/Linux x86-64 @@ -226,19 +229,18 @@ i[34567]86-*-linux*) ;; i[34567]86-*-gnu*) # Target: Intel 386 running the GNU Hurd - gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o \ - solib.o solib-svr4.o" + gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o solib-svr4.o" ;; i[34567]86-*-cygwin*) # Target: Intel 386 running win32 gdb_target_obs="i386-tdep.o i386-cygwin-tdep.o i387-tdep.o \ - solib-target.o corelow.o windows-tdep.o" + windows-tdep.o" build_gdbserver=yes ;; i[34567]86-*-mingw32*) # Target: Intel 386 running win32 gdb_target_obs="i386-tdep.o i386-cygwin-tdep.o i387-tdep.o \ - solib-target.o corelow.o windows-tdep.o" + windows-tdep.o" build_gdbserver=yes ;; i[34567]86-*-*) @@ -253,9 +255,13 @@ ia64-*-hpux*) ia64-*-linux*) # Target: Intel IA-64 running GNU/Linux gdb_target_obs="ia64-tdep.o ia64-linux-tdep.o linux-tdep.o \ - solib.o solib-svr4.o symfile-mem.o" + solib-svr4.o symfile-mem.o" build_gdbserver=yes ;; +ia64-*-*vms*) + # Target: Intel IA-64 running OpenVMS + gdb_target_obs="ia64-tdep.o ia64-vms-tdep.o" + ;; ia64*-*-*) # Target: Intel IA-64 gdb_target_obs="ia64-tdep.o" @@ -273,7 +279,7 @@ lm32-*-*) m32c-*-*) # Target: Renesas M32C family - gdb_target_obs="m32c-tdep.o prologue-value.o" + gdb_target_obs="m32c-tdep.o" # There may also be a SID / CGEN simulator for this, # but we do have DJ Delorie's mini-sim. gdb_sim=../sim/m32c/libsim.a @@ -282,7 +288,7 @@ 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-svr4.o symfile-mem.o \ linux-tdep.o" gdb_sim=../sim/m32r/libsim.a build_gdbserver=yes @@ -307,37 +313,34 @@ 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 \ + gdb_target_obs="m68k-tdep.o m68klinux-tdep.o solib-svr4.o \ linux-tdep.o glibc-tdep.o symfile-mem.o" build_gdbserver=yes ;; m68*-*-netbsd* | m68*-*-knetbsd*-gnu) # Target: NetBSD/m68k - gdb_target_obs="m68k-tdep.o m68kbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + gdb_target_obs="m68k-tdep.o m68kbsd-tdep.o solib-svr4.o" ;; m68*-*-openbsd*) # Target: OpenBSD/m68k - gdb_target_obs="m68k-tdep.o m68kbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + gdb_target_obs="m68k-tdep.o m68kbsd-tdep.o solib-svr4.o" ;; m88*-*-openbsd*) # Target: OpenBSD/m88k - gdb_target_obs="m88k-tdep.o corelow.o" + gdb_target_obs="m88k-tdep.o" ;; mep-*-*) # Target: Toshiba Media Processor (MEP) - gdb_target_obs="mep-tdep.o prologue-value.o" + gdb_target_obs="mep-tdep.o" # No sim needed. Target uses SID. ;; microblaze*-linux-*|microblaze*-*-linux*) # Target: Xilinx MicroBlaze running Linux gdb_target_obs="microblaze-tdep.o microblaze-linux-tdep.o microblaze-rom.o \ - monitor.o dsrec.o solib.o solib-svr4.o corelow.o \ - symfile-mem.o linux-tdep.o" + monitor.o dsrec.o solib-svr4.o symfile-mem.o linux-tdep.o" gdb_sim=../sim/microblaze/libsim.a ;; microblaze*-*-*) @@ -348,30 +351,27 @@ microblaze*-*-*) mips*-sgi-irix5*) # Target: MIPS SGI running Irix 5 - gdb_target_obs="mips-tdep.o mips-irix-tdep.o solib.o solib-irix.o" + gdb_target_obs="mips-tdep.o mips-irix-tdep.o solib-irix.o" ;; mips*-sgi-irix6*) # Target: MIPS SGI running Irix 6.x - gdb_target_obs="mips-tdep.o mips-irix-tdep.o solib.o solib-irix.o" + gdb_target_obs="mips-tdep.o mips-irix-tdep.o solib-irix.o" ;; 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 \ - linux-tdep.o" + solib-svr4.o symfile-mem.o linux-tdep.o" gdb_sim=../sim/mips/libsim.a build_gdbserver=yes ;; mips*-*-netbsd* | mips*-*-knetbsd*-gnu) # Target: MIPS running NetBSD - gdb_target_obs="mips-tdep.o mipsnbsd-tdep.o \ - corelow.o solib.o solib-svr4.o nbsd-tdep.o" + gdb_target_obs="mips-tdep.o mipsnbsd-tdep.o solib-svr4.o nbsd-tdep.o" gdb_sim=../sim/mips/libsim.a ;; mips64*-*-openbsd*) # Target: OpenBSD/mips64 - gdb_target_obs="mips-tdep.o mips64obsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + gdb_target_obs="mips-tdep.o mips64obsd-tdep.o solib-svr4.o" ;; mips*-*-elf) # Target: MIPS ELF @@ -395,34 +395,53 @@ mt-*-*) gdb_target_obs="mt-tdep.o" ;; +powerpc*-*-freebsd*) + # Target: FreeBSD/powerpc + gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \ + ppcfbsd-tdep.o solib-svr4.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" + ;; + powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu) # Target: NetBSD/powerpc gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppcnbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + solib-svr4.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" gdb_sim=../sim/ppc/libsim.a ;; powerpc-*-openbsd*) # Target: OpenBSD/powerpc gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppcobsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + solib-svr4.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" ;; powerpc-*-aix* | rs6000-*-*) # Target: PowerPC running AIX gdb_target_obs="rs6000-tdep.o rs6000-aix-tdep.o xcoffread.o \ - ppc-sysv-tdep.o solib.o solib-svr4.o" + ppc-sysv-tdep.o solib-svr4.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" ;; 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 solib-spu.o spu-multiarch.o \ - corelow.o symfile-mem.o linux-tdep.o" + ppc64-tdep.o solib-svr4.o solib-spu.o \ + spu-multiarch.o \ + glibc-tdep.o symfile-mem.o linux-tdep.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" gdb_sim=../sim/ppc/libsim.a build_gdbserver=yes ;; +powerpc-*-lynx*178) + # Target: PowerPC running Lynx178. + gdb_target_obs="rs6000-tdep.o rs6000-lynx178-tdep.o \ + xcoffread.o monitor.o dsrec.o ppc-sysv-tdep.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" + ;; powerpc*-*-*) # Target: PowerPC running eabi gdb_target_obs="rs6000-tdep.o monitor.o dsrec.o ppcbug-rom.o \ - dink32-rom.o ppc-sysv-tdep.o solib.o solib-svr4.o" + dink32-rom.o ppc-sysv-tdep.o solib-svr4.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" if test -f ../sim/ppc/Makefile; then gdb_sim=../sim/ppc/libsim.a fi @@ -430,10 +449,16 @@ powerpc*-*-*) s390*-*-*) # Target: S390 running Linux - gdb_target_obs="s390-tdep.o solib.o solib-svr4.o linux-tdep.o" + gdb_target_obs="s390-tdep.o solib-svr4.o linux-tdep.o" build_gdbserver=yes ;; +rl78-*-elf) + # Target: Renesas rl78 + gdb_target_obs="rl78-tdep.o" + gdb_sim=../sim/rl78/libsim.a + ;; + rx-*-elf) # Target: Renesas RX gdb_target_obs="rx-tdep.o" @@ -442,7 +467,7 @@ rx-*-elf) score-*-*) # Target: S+core embedded system - gdb_target_obs="score-tdep.o corelow.o" + gdb_target_obs="score-tdep.o" if test -f ../sim/score/Makefile; then gdb_sim=../sim/score/libsim.a fi @@ -452,20 +477,19 @@ 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 corelow.o linux-tdep.o" + dsrec.o solib-svr4.o symfile-mem.o \ + glibc-tdep.o linux-tdep.o" gdb_sim=../sim/sh/libsim.a build_gdbserver=yes ;; sh*-*-netbsdelf* | sh*-*-knetbsd*-gnu) # Target: NetBSD/sh - gdb_target_obs="sh-tdep.o shnbsd-tdep.o corelow.o solib.o solib-svr4.o" + gdb_target_obs="sh-tdep.o shnbsd-tdep.o solib-svr4.o" gdb_sim=../sim/sh/libsim.a ;; sh*-*-openbsd*) # Target: OpenBSD/sh - gdb_target_obs="sh-tdep.o sh64-tdep.o shnbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + gdb_target_obs="sh-tdep.o sh64-tdep.o shnbsd-tdep.o solib-svr4.o" ;; sh64-*-elf*) # Target: Renesas/Super-H 64 bit with simulator @@ -481,69 +505,77 @@ 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 \ - linux-tdep.o" + sparc-linux-tdep.o solib-svr4.o symfile-mem.o \ + linux-tdep.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" if test "x$enable_64_bit_bfd" = "xyes"; then # Target: GNU/Linux UltraSPARC gdb_target_obs="sparc64-tdep.o sparc64-sol2-tdep.o \ sparc64-linux-tdep.o ${gdb_target_obs}" fi + build_gdbserver=yes ;; 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 linux-tdep.o" + sparc-linux-tdep.o solib-svr4.o linux-tdep.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" build_gdbserver=yes ;; sparc*-*-freebsd* | sparc*-*-kfreebsd*-gnu) # Target: FreeBSD/sparc64 gdb_target_obs="sparc-tdep.o sparc64-tdep.o sparc64fbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + solib-svr4.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" ;; sparc-*-netbsd* | sparc-*-knetbsd*-gnu) # Target: NetBSD/sparc gdb_target_obs="sparc-tdep.o sparcnbsd-tdep.o nbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + solib-svr4.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" ;; sparc64-*-netbsd* | sparc64-*-knetbsd*-gnu) # Target: NetBSD/sparc64 gdb_target_obs="sparc64-tdep.o sparc64nbsd-tdep.o sparc-tdep.o \ - sparcnbsd-tdep.o nbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + sparcnbsd-tdep.o nbsd-tdep.o solib-svr4.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" ;; sparc-*-openbsd*) # Target: OpenBSD/sparc gdb_target_obs="sparc-tdep.o sparcnbsd-tdep.o sparcobsd-tdep.o \ - nbsd-tdep.o obsd-tdep.o bsd-uthread.o \ - corelow.o solib.o solib-svr4.o" + nbsd-tdep.o obsd-tdep.o bsd-uthread.o solib-svr4.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" ;; sparc64-*-openbsd*) # Target: OpenBSD/sparc64 gdb_target_obs="sparc64-tdep.o sparc64nbsd-tdep.o sparc64obsd-tdep.o \ sparc-tdep.o sparcnbsd-tdep.o sparcobsd-tdep.o \ - nbsd-tdep.o obsd-tdep.o bsd-uthread.o \ - corelow.o solib.o solib-svr4.o" + nbsd-tdep.o obsd-tdep.o bsd-uthread.o solib-svr4.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" ;; sparc-*-solaris2.[0-6] | sparc-*-solaris2.[0-6].*) # Target: Solaris SPARC gdb_target_obs="sparc-tdep.o sparc-sol2-tdep.o sol2-tdep.o \ - solib.o solib-svr4.o" + solib-svr4.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" ;; sparc-*-solaris2* | sparcv9-*-solaris2* | sparc64-*-solaris2*) # Target: Solaris UltraSPARC gdb_target_obs="sparc64-tdep.o sparc64-sol2-tdep.o sparc-tdep.o \ - sparc-sol2-tdep.o sol2-tdep.o solib.o solib-svr4.o" + sparc-sol2-tdep.o sol2-tdep.o solib-svr4.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" ;; sparc-*-*) # Target: SPARC - gdb_target_obs="sparc-tdep.o ravenscar-thread.o \ - ravenscar-sparc-thread.o" + gdb_target_obs="sparc-tdep.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" gdb_sim=../sim/erc32/libsim.a ;; sparc64-*-*) # Target: UltraSPARC - gdb_target_obs="sparc-tdep.o sparc64-tdep.o" + gdb_target_obs="sparc-tdep.o sparc64-tdep.o \ + ravenscar-thread.o sparc-ravenscar-thread.o" ;; spu*-*-*) @@ -555,7 +587,7 @@ spu*-*-*) tic6x-*-*linux) # Target: GNU/Linux TI C6x gdb_target_obs="tic6x-tdep.o tic6x-linux-tdep.o solib-dsbt.o \ - glibc-tdep.o corelow.o linux-tdep.o" + glibc-tdep.o linux-tdep.o" ;; tic6x-*-*) @@ -563,13 +595,20 @@ tic6x-*-*) gdb_target_obs="tic6x-tdep.o" ;; +tilegx-*-linux*) + # Target: TILE-Gx + gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \ + symfile-mem.o glibc-tdep.o linux-tdep.o" + build_gdbserver=yes + ;; + xstormy16-*-*) # Target: Sanyo Xstormy16a processor gdb_target_obs="xstormy16-tdep.o" # No simulator libraries are needed -- target uses SID. ;; -v850*-*-elf) +v850*-*-elf | v850*-*-rtems*) # Target: NEC V850 processor gdb_target_obs="v850-tdep.o" gdb_sim=../sim/v850/libsim.a @@ -577,12 +616,11 @@ v850*-*-elf) vax-*-netbsd* | vax-*-knetbsd*-gnu) # Target: NetBSD/vax - gdb_target_obs="vax-tdep.o vaxnbsd-tdep.o \ - corelow.o solib.o solib-svr4.o" + gdb_target_obs="vax-tdep.o vaxnbsd-tdep.o solib-svr4.o" ;; vax-*-openbsd*) # Target: OpenBSD/vax - gdb_target_obs="vax-tdep.o vaxobsd-tdep.o corelow.o" + gdb_target_obs="vax-tdep.o vaxobsd-tdep.o" ;; vax-*-*) # Target: VAX running 4.2BSD or Ultrix @@ -593,57 +631,54 @@ x86_64-*-darwin*) # Target: Darwin/x86-64 gdb_target_obs="amd64-tdep.o i386-tdep.o i387-tdep.o \ i386-darwin-tdep.o amd64-darwin-tdep.o \ - solib.o solib-darwin.o" + solib-darwin.o" ;; x86_64-*-dicos*) # Target: DICOS/x86-64 gdb_target_obs="amd64-tdep.o i386-tdep.o i387-tdep.o \ - dicos-tdep.o i386-dicos-tdep.o amd64-dicos-tdep.o \ - corelow.o solib.o solib-target.o" + dicos-tdep.o i386-dicos-tdep.o amd64-dicos-tdep.o" ;; x86_64-*-linux*) # Target: GNU/Linux x86-64 gdb_target_obs="amd64-tdep.o amd64-linux-tdep.o i386-tdep.o \ i387-tdep.o i386-linux-tdep.o glibc-tdep.o \ - solib.o solib-svr4.o corelow.o symfile-mem.o linux-tdep.o \ - linux-record.o" + solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o" build_gdbserver=yes ;; x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) # Target: FreeBSD/amd64 gdb_target_obs="amd64-tdep.o amd64fbsd-tdep.o i386-tdep.o \ i387-tdep.o i386bsd-tdep.o i386fbsd-tdep.o \ - bsd-uthread.o corelow.o solib.o solib-svr4.o" + bsd-uthread.o solib-svr4.o" ;; -x86_64-*-mingw*) +x86_64-*-mingw* | x86_64-*-cygwin*) # Target: MingW/amd64 gdb_target_obs="amd64-tdep.o amd64-windows-tdep.o \ i386-tdep.o i386-cygwin-tdep.o i387-tdep.o \ - solib-target.o windows-tdep.o" + windows-tdep.o" build_gdbserver=yes ;; x86_64-*-netbsd* | x86_64-*-knetbsd*-gnu) # Target: NetBSD/amd64 gdb_target_obs="amd64-tdep.o amd64nbsd-tdep.o i386-tdep.o i387-tdep.o \ - nbsd-tdep.o corelow.o solib.o solib-svr4.o" + nbsd-tdep.o solib-svr4.o" ;; x86_64-*-openbsd*) # Target: OpenBSD/amd64 gdb_target_obs="amd64-tdep.o amd64obsd-tdep.o i386-tdep.o \ i387-tdep.o i386bsd-tdep.o i386obsd-tdep.o \ - bsd-uthread.o corelow.o solib.o solib-svr4.o" + bsd-uthread.o solib-svr4.o" ;; 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 \ - linux-tdep.o" + solib-svr4.o symfile-mem.o linux-tdep.o" build_gdbserver=yes ;; xtensa*) # Target: Tensilica Xtensa processors - gdb_target_obs="xtensa-tdep.o xtensa-config.o solib.o solib-svr4.o" + gdb_target_obs="xtensa-tdep.o xtensa-config.o solib-svr4.o" ;; esac diff --git a/contrib/gdb-7/gdb/continuations.c b/contrib/gdb-7/gdb/continuations.c index 95e934e59e..2dfbbb3368 100644 --- a/contrib/gdb-7/gdb/continuations.c +++ b/contrib/gdb-7/gdb/continuations.c @@ -1,6 +1,6 @@ /* Continuations for GDB, the GNU debugger. - Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -100,8 +100,6 @@ discard_my_continuations_1 (struct continuation **pmy_chain) static void discard_my_continuations (struct continuation **list) { - struct continuation *continuation_ptr = *list; - discard_my_continuations_1 (list); *list = NULL; } diff --git a/contrib/gdb-7/gdb/continuations.h b/contrib/gdb-7/gdb/continuations.h index 1c7d1d9540..d72735bea2 100644 --- a/contrib/gdb-7/gdb/continuations.h +++ b/contrib/gdb-7/gdb/continuations.h @@ -1,6 +1,6 @@ /* Continuations for GDB, the GNU debugger. - Copyright (C) 1999-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/copying.c b/contrib/gdb-7/gdb/copying.c index d608a63669..66837b87fd 100644 --- a/contrib/gdb-7/gdb/copying.c +++ b/contrib/gdb-7/gdb/copying.c @@ -1,5 +1,6 @@ -/* ==> Do not modify this file!! It is created automatically - by copying.awk. Modify copying.awk instead. <== */ +/* ==> Do not modify this file!! -*- buffer-read-only: t -*- vi:set ro: + It is created automatically by copying.awk. + Modify copying.awk instead. <== */ #include "defs.h" #include "command.h" @@ -11,11 +12,9 @@ static void show_warranty_command (char *, int); void _initialize_copying (void); -extern int immediate_quit; static void show_copying_command (char *ignore, int from_tty) { - immediate_quit++; printf_filtered (" GNU GENERAL PUBLIC LICENSE\n"); printf_filtered (" Version 3, 29 June 2007\n"); printf_filtered ("\n"); @@ -604,13 +603,11 @@ show_copying_command (char *ignore, int from_tty) printf_filtered ("author or copyright holder as a result of your choosing to follow a\n"); printf_filtered ("later version.\n"); printf_filtered ("\n"); - immediate_quit--; } static void show_warranty_command (char *ignore, int from_tty) { - immediate_quit++; printf_filtered (" 15. Disclaimer of Warranty.\n"); printf_filtered ("\n"); printf_filtered (" THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\n"); @@ -643,7 +640,6 @@ show_warranty_command (char *ignore, int from_tty) printf_filtered ("Program, unless a warranty or assumption of liability accompanies a\n"); printf_filtered ("copy of the Program in return for a fee.\n"); printf_filtered ("\n"); - immediate_quit--; } void diff --git a/contrib/gdb-7/gdb/copyright.py b/contrib/gdb-7/gdb/copyright.py index 71f261d68f..1af0f4816e 100644 --- a/contrib/gdb-7/gdb/copyright.py +++ b/contrib/gdb-7/gdb/copyright.py @@ -1,608 +1,278 @@ #! /usr/bin/env python +# Copyright (C) 2011-2013 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 . + """copyright.py -This script updates most of the files that are not already handled -by copyright.sh. It must be run from the gdb/ subdirectory of the -GDB source tree. +This script updates the list of years in the copyright notices in +most files maintained by the GDB project. + +Usage: cd src/gdb && python copyright.py +Always review the output of this script before committing it! +A useful command to review the output is: + % filterdiff -x \*.c -x \*.cc -x \*.h -x \*.exp updates.diff +This removes the bulk of the changes which are most likely to be correct. """ import datetime -import re import os import os.path +import subprocess + -class Comment(object): - """A class describing comment. - - ATTRIBUTES - start: A string describing how comments are started. - stop: A string describing how comments end. If None, then - a comment ends at the end of the line. - start2: Some files accept more than 1 kind of comment. - For those that do, this is the alternative form. - For now, it is assumed that if start2 is not None, - then stop is None (thus no stop2 attribute). +def get_update_list(): + """Return the list of files to update. + + Assumes that the current working directory when called is the root + of the GDB source tree (NOT the gdb/ subdirectory!). The names of + the files are relative to that root directory. + """ + result = [] + for gdb_dir in ('gdb', 'sim', 'include/gdb'): + for root, dirs, files in os.walk(gdb_dir, topdown=True): + for dirname in dirs: + reldirname = "%s/%s" % (root, dirname) + if (dirname in EXCLUDE_ALL_LIST + or reldirname in EXCLUDE_LIST + or reldirname in NOT_FSF_LIST + or reldirname in BY_HAND): + # Prune this directory from our search list. + dirs.remove(dirname) + for filename in files: + relpath = "%s/%s" % (root, filename) + if (filename in EXCLUDE_ALL_LIST + or relpath in EXCLUDE_LIST + or relpath in NOT_FSF_LIST + or relpath in BY_HAND): + # Ignore this file. + pass + else: + result.append(relpath) + return result + + +def update_files(update_list): + """Update the copyright header of the files in the given list. + + We use gnulib's update-copyright script for that. """ - def __init__(self, start, stop=None, start2=None, max_lines=30): - """The "Copyright" keyword should be within MAX_LINES lines - from the start of the file.""" - self.start = start - self.stop = stop - self.start2 = start2 - self.max_lines = max_lines + # We want to use year intervals in the copyright notices, and + # all years should be collapsed to one single year interval, + # even if there are "holes" in the list of years found in the + # original copyright notice (OK'ed by the FSF, case [gnu.org #719834]). + os.environ['UPDATE_COPYRIGHT_USE_INTERVALS'] = '2' + + # Perform the update, and save the output in a string. + update_cmd = ['bash', 'gdb/gnulib/import/extra/update-copyright'] + update_cmd += update_list + + p = subprocess.Popen(update_cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + update_out = p.communicate()[0] + + # Process the output. Typically, a lot of files do not have + # a copyright notice :-(. The update-copyright script prints + # a well defined warning when it did not find the copyright notice. + # For each of those, do a sanity check and see if they may in fact + # have one. For the files that are found not to have one, we filter + # the line out from the output, since there is nothing more to do, + # short of looking at each file and seeing which notice is appropriate. + # Too much work! (~4,000 files listed as of 2012-01-03). + update_out = update_out.splitlines() + warning_string = ': warning: copyright statement not found' + warning_len = len(warning_string) + + for line in update_out: + if line.endswith('\n'): + line = line[:-1] + if line.endswith(warning_string): + filename = line[:-warning_len] + if may_have_copyright_notice(filename): + print line + else: + # Unrecognized file format. !?! + print "*** " + line + + +def may_have_copyright_notice(filename): + """Check that the given file does not seem to have a copyright notice. -# The Comment object for Ada code (and GPR files). -ADA_COMMENT = Comment(start="--") + The filename is relative to the root directory. + This function assumes that the current working directory is that root + directory. -THIS_YEAR = str(datetime.date.today().year) + The algorigthm is fairly crude, meaning that it might return + some false positives. I do not think it will return any false + negatives... We might improve this function to handle more + complex cases later... + """ + # For now, it may have a copyright notice if we find the word + # "Copyright" at the (reasonable) start of the given file, say + # 50 lines... + MAX_LINES = 50 + + fd = open(filename) + + lineno = 1 + for line in fd: + if 'Copyright' in line: + return True + lineno += 1 + if lineno > 50: + return False + return False + + +def main (): + """The main subprogram.""" + if not os.path.isfile("gnulib/import/extra/update-copyright"): + print "Error: This script must be called from the gdb directory." + root_dir = os.path.dirname(os.getcwd()) + os.chdir(root_dir) + + update_list = get_update_list() + update_files (update_list) + + # Remind the user that some files need to be updated by HAND... + if BY_HAND: + print + print "\033[31mREMINDER: The following files must be updated by hand." \ + "\033[0m" + for filename in BY_HAND + MULTIPLE_COPYRIGHT_HEADERS: + print " ", filename + +############################################################################ +# +# Some constants, placed at the end because they take up a lot of room. +# The actual value of these constants is not significant to the understanding +# of the script. +# +############################################################################ # Files which should not be modified, either because they are # generated, non-FSF, or otherwise special (e.g. license text, # or test cases which must be sensitive to line numbering). -EXCLUSION_LIST = ( - "COPYING", "COPYING.LIB", "CVS", "configure", "copying.c", "gdbarch.c", - "gdbarch.h", "fdl.texi", "gpl.texi", "gdbtk", "gdb.gdbtk", "osf-share", - "aclocal.m4", "step-line.inp", "step-line.c", - ) - -# Files that are too different from the rest to be processed automatically. -BY_HAND = ['../sim/ppc/psim.texinfo'] - -# Files for which we know that they do not have a copyright header. -# Ideally, this list should be empty (but it may not be possible to -# add a copyright header in some of them). -NO_COPYRIGHT = ( - # Configure files. We should fix those, one day. - "testsuite/gdb.cell/configure.ac", "testsuite/gdb.hp/configure.ac", - "testsuite/gdb.hp/gdb.aCC/configure.ac", - "testsuite/gdb.hp/gdb.base-hp/configure.ac", - "testsuite/gdb.hp/gdb.compat/configure.ac", - "testsuite/gdb.hp/gdb.defects/configure.ac", - "testsuite/gdb.hp/gdb.objdbg/configure.ac", - "testsuite/gdb.stabs/configure.ac", - "../sim/arm/configure.ac", "../sim/avr/configure.ac", - "../sim/common/configure.ac", "../sim/configure.ac", - "../sim/cr16/configure.ac", "../sim/cris/configure.ac", - "../sim/d10v/configure.ac", "../sim/erc32/configure.ac", - "../sim/frv/configure.ac", "../sim/h8300/configure.ac", - "../sim/igen/configure.ac", "../sim/iq2000/configure.ac", - "../sim/lm32/configure.ac", "../sim/m32r/configure.ac", - "../sim/m68hc11/configure.ac", "../sim/mcore/configure.ac", - "../sim/microblaze/configure.ac", "../sim/mips/configure.ac", - "../sim/mn10300/configure.ac", "../sim/moxie/configure.ac", - "../sim/ppc/configure.ac", "../sim/sh/configure.ac", - "../sim/sh64/configure.ac", "../sim/testsuite/configure.ac", - "../sim/testsuite/d10v-elf/configure.ac", - "../sim/testsuite/frv-elf/configure.ac", - "../sim/testsuite/m32r-elf/configure.ac", - "../sim/testsuite/mips64el-elf/configure.ac", "../sim/v850/configure.ac", - # Assembly files. It's not certain that we can add a copyright - # header in a way that works for all platforms supported by the - # testcase... - "testsuite/gdb.arch/pa-nullify.s", "testsuite/gdb.arch/pa64-nullify.s", - "testsuite/gdb.asm/asmsrc1.s", "testsuite/gdb.asm/asmsrc2.s", - "testsuite/gdb.disasm/am33.s", "testsuite/gdb.disasm/h8300s.s", - "testsuite/gdb.disasm/hppa.s", "testsuite/gdb.disasm/mn10200.s", - "testsuite/gdb.disasm/mn10300.s", "testsuite/gdb.disasm/sh3.s", - "testsuite/gdb.disasm/t01_mov.s", "testsuite/gdb.disasm/t02_mova.s", - "testsuite/gdb.disasm/t03_add.s", "testsuite/gdb.disasm/t04_sub.s", - "testsuite/gdb.disasm/t05_cmp.s", "testsuite/gdb.disasm/t06_ari2.s", - "testsuite/gdb.disasm/t07_ari3.s", "testsuite/gdb.disasm/t08_or.s", - "testsuite/gdb.disasm/t09_xor.s", "testsuite/gdb.disasm/t10_and.s", - "testsuite/gdb.disasm/t11_logs.s", "testsuite/gdb.disasm/t12_bit.s", - "testsuite/gdb.disasm/t13_otr.s", "testsuite/gdb.hp/gdb.base-hp/reg-pa64.s", - "testsuite/gdb.hp/gdb.base-hp/reg.s", - "../sim/testsuite/d10v-elf/exit47.s", - "../sim/testsuite/d10v-elf/hello.s", - "../sim/testsuite/d10v-elf/loop.s", - "../sim/testsuite/d10v-elf/t-ae-ld-d.s", - "../sim/testsuite/d10v-elf/t-ae-ld-i.s", - "../sim/testsuite/d10v-elf/t-ae-ld-id.s", - "../sim/testsuite/d10v-elf/t-ae-ld-im.s", - "../sim/testsuite/d10v-elf/t-ae-ld-ip.s", - "../sim/testsuite/d10v-elf/t-ae-ld2w-d.s", - "../sim/testsuite/d10v-elf/t-ae-ld2w-i.s", - "../sim/testsuite/d10v-elf/t-ae-ld2w-id.s", - "../sim/testsuite/d10v-elf/t-ae-ld2w-im.s", - "../sim/testsuite/d10v-elf/t-ae-ld2w-ip.s", - "../sim/testsuite/d10v-elf/t-ae-st-d.s", - "../sim/testsuite/d10v-elf/t-ae-st-i.s", - "../sim/testsuite/d10v-elf/t-ae-st-id.s", - "../sim/testsuite/d10v-elf/t-ae-st-im.s", - "../sim/testsuite/d10v-elf/t-ae-st-ip.s", - "../sim/testsuite/d10v-elf/t-ae-st-is.s", - "../sim/testsuite/d10v-elf/t-ae-st2w-d.s", - "../sim/testsuite/d10v-elf/t-ae-st2w-i.s", - "../sim/testsuite/d10v-elf/t-ae-st2w-id.s", - "../sim/testsuite/d10v-elf/t-ae-st2w-im.s", - "../sim/testsuite/d10v-elf/t-ae-st2w-ip.s", - "../sim/testsuite/d10v-elf/t-ae-st2w-is.s", - "../sim/testsuite/d10v-elf/t-dbt.s", - "../sim/testsuite/d10v-elf/t-ld-st.s", - "../sim/testsuite/d10v-elf/t-mac.s", - "../sim/testsuite/d10v-elf/t-mod-ld-pre.s", - "../sim/testsuite/d10v-elf/t-msbu.s", - "../sim/testsuite/d10v-elf/t-mulxu.s", - "../sim/testsuite/d10v-elf/t-mvtac.s", - "../sim/testsuite/d10v-elf/t-mvtc.s", - "../sim/testsuite/d10v-elf/t-rac.s", - "../sim/testsuite/d10v-elf/t-rachi.s", - "../sim/testsuite/d10v-elf/t-rdt.s", - "../sim/testsuite/d10v-elf/t-rep.s", - "../sim/testsuite/d10v-elf/t-rie-xx.s", - "../sim/testsuite/d10v-elf/t-rte.s", - "../sim/testsuite/d10v-elf/t-sac.s", - "../sim/testsuite/d10v-elf/t-sachi.s", - "../sim/testsuite/d10v-elf/t-sadd.s", - "../sim/testsuite/d10v-elf/t-slae.s", - "../sim/testsuite/d10v-elf/t-sp.s", - "../sim/testsuite/d10v-elf/t-sub.s", - "../sim/testsuite/d10v-elf/t-sub2w.s", - "../sim/testsuite/d10v-elf/t-subi.s", - "../sim/testsuite/d10v-elf/t-trap.s", - "../sim/testsuite/frv-elf/cache.s", - "../sim/testsuite/frv-elf/exit47.s", - "../sim/testsuite/frv-elf/grloop.s", - "../sim/testsuite/frv-elf/hello.s", - "../sim/testsuite/frv-elf/loop.s", - "../sim/testsuite/m32r-elf/exit47.s", - "../sim/testsuite/m32r-elf/hello.s", - "../sim/testsuite/m32r-elf/loop.s", - "../sim/testsuite/sim/cris/hw/rv-n-cris/quit.s", - "../sim/testsuite/sim/h8300/addb.s", - "../sim/testsuite/sim/h8300/addl.s", - "../sim/testsuite/sim/h8300/adds.s", - "../sim/testsuite/sim/h8300/addw.s", - "../sim/testsuite/sim/h8300/addx.s", - "../sim/testsuite/sim/h8300/andb.s", - "../sim/testsuite/sim/h8300/andl.s", - "../sim/testsuite/sim/h8300/andw.s", - "../sim/testsuite/sim/h8300/band.s", - "../sim/testsuite/sim/h8300/bfld.s", - "../sim/testsuite/sim/h8300/biand.s", - "../sim/testsuite/sim/h8300/bra.s", - "../sim/testsuite/sim/h8300/brabc.s", - "../sim/testsuite/sim/h8300/bset.s", - "../sim/testsuite/sim/h8300/cmpb.s", - "../sim/testsuite/sim/h8300/cmpl.s", - "../sim/testsuite/sim/h8300/cmpw.s", - "../sim/testsuite/sim/h8300/daa.s", - "../sim/testsuite/sim/h8300/das.s", - "../sim/testsuite/sim/h8300/dec.s", - "../sim/testsuite/sim/h8300/div.s", - "../sim/testsuite/sim/h8300/extl.s", - "../sim/testsuite/sim/h8300/extw.s", - "../sim/testsuite/sim/h8300/inc.s", - "../sim/testsuite/sim/h8300/jmp.s", - "../sim/testsuite/sim/h8300/ldc.s", - "../sim/testsuite/sim/h8300/ldm.s", - "../sim/testsuite/sim/h8300/mac.s", - "../sim/testsuite/sim/h8300/mova.s", - "../sim/testsuite/sim/h8300/movb.s", - "../sim/testsuite/sim/h8300/movl.s", - "../sim/testsuite/sim/h8300/movmd.s", - "../sim/testsuite/sim/h8300/movsd.s", - "../sim/testsuite/sim/h8300/movw.s", - "../sim/testsuite/sim/h8300/mul.s", - "../sim/testsuite/sim/h8300/neg.s", - "../sim/testsuite/sim/h8300/nop.s", - "../sim/testsuite/sim/h8300/not.s", - "../sim/testsuite/sim/h8300/orb.s", - "../sim/testsuite/sim/h8300/orl.s", - "../sim/testsuite/sim/h8300/orw.s", - "../sim/testsuite/sim/h8300/rotl.s", - "../sim/testsuite/sim/h8300/rotr.s", - "../sim/testsuite/sim/h8300/rotxl.s", - "../sim/testsuite/sim/h8300/rotxr.s", - "../sim/testsuite/sim/h8300/shal.s", - "../sim/testsuite/sim/h8300/shar.s", - "../sim/testsuite/sim/h8300/shll.s", - "../sim/testsuite/sim/h8300/shlr.s", - "../sim/testsuite/sim/h8300/stack.s", - "../sim/testsuite/sim/h8300/stc.s", - "../sim/testsuite/sim/h8300/subb.s", - "../sim/testsuite/sim/h8300/subl.s", - "../sim/testsuite/sim/h8300/subs.s", - "../sim/testsuite/sim/h8300/subw.s", - "../sim/testsuite/sim/h8300/subx.s", - "../sim/testsuite/sim/h8300/tas.s", - "../sim/testsuite/sim/h8300/xorb.s", - "../sim/testsuite/sim/h8300/xorl.s", - "../sim/testsuite/sim/h8300/xorw.s", - "../sim/testsuite/sim/mips/fpu64-ps-sb1.s", - "../sim/testsuite/sim/mips/fpu64-ps.s", - "../sim/testsuite/sim/mips/hilo-hazard-1.s", - "../sim/testsuite/sim/mips/hilo-hazard-2.s", - "../sim/testsuite/sim/mips/hilo-hazard-3.s", - "../sim/testsuite/sim/mips/mdmx-ob-sb1.s", - "../sim/testsuite/sim/mips/mdmx-ob.s", - "../sim/testsuite/sim/mips/mips32-dsp.s", - "../sim/testsuite/sim/mips/mips32-dsp2.s", - "../sim/testsuite/sim/mips/sanity.s", - "../sim/testsuite/sim/sh/add.s", - "../sim/testsuite/sim/sh/and.s", - "../sim/testsuite/sim/sh/bandor.s", - "../sim/testsuite/sim/sh/bandornot.s", - "../sim/testsuite/sim/sh/bclr.s", - "../sim/testsuite/sim/sh/bld.s", - "../sim/testsuite/sim/sh/bldnot.s", - "../sim/testsuite/sim/sh/bset.s", - "../sim/testsuite/sim/sh/bst.s", - "../sim/testsuite/sim/sh/bxor.s", - "../sim/testsuite/sim/sh/clip.s", - "../sim/testsuite/sim/sh/div.s", - "../sim/testsuite/sim/sh/dmxy.s", - "../sim/testsuite/sim/sh/fabs.s", - "../sim/testsuite/sim/sh/fadd.s", - "../sim/testsuite/sim/sh/fail.s", - "../sim/testsuite/sim/sh/fcmpeq.s", - "../sim/testsuite/sim/sh/fcmpgt.s", - "../sim/testsuite/sim/sh/fcnvds.s", - "../sim/testsuite/sim/sh/fcnvsd.s", - "../sim/testsuite/sim/sh/fdiv.s", - "../sim/testsuite/sim/sh/fipr.s", - "../sim/testsuite/sim/sh/fldi0.s", - "../sim/testsuite/sim/sh/fldi1.s", - "../sim/testsuite/sim/sh/flds.s", - "../sim/testsuite/sim/sh/float.s", - "../sim/testsuite/sim/sh/fmac.s", - "../sim/testsuite/sim/sh/fmov.s", - "../sim/testsuite/sim/sh/fmul.s", - "../sim/testsuite/sim/sh/fneg.s", - "../sim/testsuite/sim/sh/fpchg.s", - "../sim/testsuite/sim/sh/frchg.s", - "../sim/testsuite/sim/sh/fsca.s", - "../sim/testsuite/sim/sh/fschg.s", - "../sim/testsuite/sim/sh/fsqrt.s", - "../sim/testsuite/sim/sh/fsrra.s", - "../sim/testsuite/sim/sh/fsub.s", - "../sim/testsuite/sim/sh/ftrc.s", - "../sim/testsuite/sim/sh/ldrc.s", - "../sim/testsuite/sim/sh/loop.s", - "../sim/testsuite/sim/sh/macl.s", - "../sim/testsuite/sim/sh/macw.s", - "../sim/testsuite/sim/sh/mov.s", - "../sim/testsuite/sim/sh/movi.s", - "../sim/testsuite/sim/sh/movli.s", - "../sim/testsuite/sim/sh/movua.s", - "../sim/testsuite/sim/sh/movxy.s", - "../sim/testsuite/sim/sh/mulr.s", - "../sim/testsuite/sim/sh/pabs.s", - "../sim/testsuite/sim/sh/padd.s", - "../sim/testsuite/sim/sh/paddc.s", - "../sim/testsuite/sim/sh/pand.s", - "../sim/testsuite/sim/sh/pass.s", - "../sim/testsuite/sim/sh/pclr.s", - "../sim/testsuite/sim/sh/pdec.s", - "../sim/testsuite/sim/sh/pdmsb.s", - "../sim/testsuite/sim/sh/pinc.s", - "../sim/testsuite/sim/sh/pmuls.s", - "../sim/testsuite/sim/sh/prnd.s", - "../sim/testsuite/sim/sh/pshai.s", - "../sim/testsuite/sim/sh/pshar.s", - "../sim/testsuite/sim/sh/pshli.s", - "../sim/testsuite/sim/sh/pshlr.s", - "../sim/testsuite/sim/sh/psub.s", - "../sim/testsuite/sim/sh/pswap.s", - "../sim/testsuite/sim/sh/pushpop.s", - "../sim/testsuite/sim/sh/resbank.s", - "../sim/testsuite/sim/sh/sett.s", - "../sim/testsuite/sim/sh/shll.s", - "../sim/testsuite/sim/sh/shll16.s", - "../sim/testsuite/sim/sh/shll2.s", - "../sim/testsuite/sim/sh/shll8.s", - "../sim/testsuite/sim/sh/shlr.s", - "../sim/testsuite/sim/sh/shlr16.s", - "../sim/testsuite/sim/sh/shlr2.s", - "../sim/testsuite/sim/sh/shlr8.s", - "../sim/testsuite/sim/sh/swap.s", - "../sim/testsuite/sim/sh64/misc/fr-dr.s", - # .inc files. These are usually assembly or C files... - "testsuite/gdb.asm/alpha.inc", - "testsuite/gdb.asm/arm.inc", - "testsuite/gdb.asm/common.inc", - "testsuite/gdb.asm/empty.inc", - "testsuite/gdb.asm/frv.inc", - "testsuite/gdb.asm/h8300.inc", - "testsuite/gdb.asm/i386.inc", - "testsuite/gdb.asm/ia64.inc", - "testsuite/gdb.asm/iq2000.inc", - "testsuite/gdb.asm/m32c.inc", - "testsuite/gdb.asm/m32r-linux.inc", - "testsuite/gdb.asm/m32r.inc", - "testsuite/gdb.asm/m68hc11.inc", - "testsuite/gdb.asm/m68k.inc", - "testsuite/gdb.asm/mips.inc", - "testsuite/gdb.asm/netbsd.inc", - "testsuite/gdb.asm/openbsd.inc", - "testsuite/gdb.asm/pa.inc", - "testsuite/gdb.asm/pa64.inc", - "testsuite/gdb.asm/powerpc.inc", - "testsuite/gdb.asm/powerpc64.inc", - "testsuite/gdb.asm/s390.inc", - "testsuite/gdb.asm/s390x.inc", - "testsuite/gdb.asm/sh.inc", - "testsuite/gdb.asm/sparc.inc", - "testsuite/gdb.asm/sparc64.inc", - "testsuite/gdb.asm/spu.inc", - "testsuite/gdb.asm/v850.inc", - "testsuite/gdb.asm/x86_64.inc", - "testsuite/gdb.asm/xstormy16.inc", - "../sim/testsuite/sim/arm/iwmmxt/testutils.inc", - "../sim/testsuite/sim/arm/testutils.inc", - "../sim/testsuite/sim/arm/thumb/testutils.inc", - "../sim/testsuite/sim/arm/xscale/testutils.inc", - "../sim/testsuite/sim/cr16/testutils.inc", - "../sim/testsuite/sim/cris/asm/testutils.inc", - "../sim/testsuite/sim/cris/hw/rv-n-cris/testutils.inc", - "../sim/testsuite/sim/fr30/testutils.inc", - "../sim/testsuite/sim/frv/testutils.inc", - "../sim/testsuite/sim/h8300/testutils.inc", - "../sim/testsuite/sim/m32r/testutils.inc", - "../sim/testsuite/sim/sh/testutils.inc", - "../sim/testsuite/sim/sh64/compact/testutils.inc", - "../sim/testsuite/sim/sh64/media/testutils.inc", - "../sim/testsuite/sim/v850/testutils.inc", - ) - -# A mapping between file extensions to their associated Comment object. -# This dictionary also contains a number of exceptions, based on -# filename. -COMMENT_MAP = \ - {".1" : Comment(start=r'.\"'), - ".ac" : Comment(start="dnl", start2="#"), - ".ads" : ADA_COMMENT, - ".adb" : ADA_COMMENT, - ".f" : Comment(start="c"), - ".f90" : Comment(start="!"), - ".gpr" : ADA_COMMENT, - ".inc" : Comment(start="#", start2=";"), - ".s" : Comment(start="!"), - ".tex" : Comment(start="%"), - ".texi" : Comment(start="@c"), - ".texinfo" : Comment(start="@c"), - - # Files that use a different way of including the copyright - # header... - "ada-operator.inc" : Comment(start="/*", stop="*/"), - "gdbint.texinfo" : Comment(start='@copying', stop="@end copying"), - "annotate.texinfo" : Comment(start='@copying', stop="@end copying", - max_lines=50), - "stabs.texinfo" : Comment(start='@copying', stop="@end copying"), - } - -class NotFound(Exception): - pass - -class AlreadyDone(Exception): - pass - -def process_header(src, dst, cdescr): - """Read from SRC for up to CDESCR.MAX_LINES until we find a copyright - notice. If found, then write the entire file, with the copyright - noticed updated with the current year added. - - Raises NotFound if the copyright notice could not be found or has - some inconsistencies. - - Raises AlreadyDone if the copyright notice already includes the current - year. - """ - line_count = 0 - # The start-of-comment marker used for this file. Only really useful - # in the case where comments ends at the end of the line, as this - # allows us to know which comment marker to use when breaking long - # lines (in the cases where there are more than one. - cdescr_start = "" - - while True: - # If we still haven't found a copyright line within a certain - # number of lines, then give up. - if line_count > cdescr.max_lines: - raise NotFound("start of Copyright not found") - - line = src.readline() - line_count += 1 - if not line: - raise NotFound("start of Copyright not found (EOF)") - - # Is this a copyright line? If not, then no transformation is - # needed. Write it as is, and continue. - if not re.search(r"Copyright\b.*\b(199\d|20\d\d)\b", line): - dst.write(line) - continue - - # If a start-of-comment marker is needed for every line, try to - # figure out which one it is that is being used in this file (most - # files only accept one, in which case it's easy - but some accept - # two or more...). - if cdescr.stop is None: - stripped_line = line.lstrip() - if stripped_line.startswith(cdescr.start): - cdescr_start = cdescr.start - elif (cdescr.start2 is not None - and stripped_line.startswith(cdescr.start2)): - cdescr_start = cdescr.start2 - elif cdescr.start in stripped_line: - cdescr_start = cdescr.start - elif (cdescr.start2 is not None - and cdescr.start2 in stripped_line): - cdescr_start = cdescr.start2 - else: - # This can't be a line with a comment, so not the copyright - # line we were looking for. Ignore. - continue - - comment = line - break - - while not re.search(r"Free\s+Software\s+Foundation", comment): - line = src.readline() - line_count += 1 - if not line: - raise NotFound("Copyright owner not found (EOF)") - - if cdescr.stop is None: - # Expect a new comment marker at the start of each line - line = line.lstrip() - if not line.startswith(cdescr_start): - raise NotFound("Copyright owner not found " - "(end of comment)") - comment += " " + line[len(cdescr_start):] - else: - if cdescr.stop in comment: - raise NotFound("Copyright owner not found " - "(end of comment)") - comment += line - - # Normalize a bit the copyright string (we preserve the string - # up until "Copyright", in order to help preserve any original - # alignment. - (before, after) = comment.split("Copyright", 1) - after = after.replace("\n", " ") - after = re.sub("\s+", " ", after) - after = after.rstrip() - - # If the copyright year has already been added, the nothing else - # to do. - if THIS_YEAR in after: - raise AlreadyDone - - m = re.match("(.*[0-9]+)(.*)", after) - if m is None: - raise NotFound("Internal error - cannot split copyright line: " - "`%s'" % comment) - - # Reconstruct the comment line - comment = before + "Copyright" + m.group(1) + ', %s' % THIS_YEAR - owner_part = m.group(2).lstrip() - - # Max comment len... - max_len = 76 - - # If we have to break the copyright line into multiple lines, - # we want to align all the lines on the "Copyright" keyword. - # Create a small "indent" string that we can use for that. - if cdescr.stop is None: - # The comment marker is needed on every line, so put it at the - # start of our "indent" string. - indent = cdescr_start + ' ' * (len(before) - len(cdescr_start)) - else: - indent = ' ' * len(before) - - # If the line is too long... - while len(comment) > max_len: - # Split the line at the first space before max_len. - space_index = comment[0:max_len].rfind(' ') - if space_index < 0: # No space in the first max_len characters??? - # Split at the first space, then... - space_index = comment.find(' ') - if space_index < 0: - # Still no space found. This is extremely unlikely, but - # just pretend there is one at the end of the string. - space_index = len(comment) - - # Write the first part of the string up until the space - # we selected to break our line. - dst.write(comment[:space_index] + '\n') - - # Strip the part of comment that we have finished printing. - if space_index < len(comment): - comment = comment[space_index + 1:] - else: - comment = "" - - # Prepend the "indent" string to make sure that we remain - # aligned on the "Copyright" word. - comment = indent + comment - - # And finally, write the rest of the last line... We want to write - # "Free Software Foundation, Inc" on the same line, so handle this - # with extra care. - dst.write(comment) - if len(comment) + 1 + len (owner_part) > max_len: - dst.write('\n' + indent) - else: - dst.write(' ') - dst.write(owner_part + '\n') - -def comment_for_filename(filename): - """Return the Comment object that best describes the given file. - This a smart lookup of the COMMENT_MAP dictionary where we check - for filename-based exceptions first, before looking up the comment - by filename extension. """ - # First, consult the COMMENT_MAP using the filename, in case this - # file needs special treatment. - basename = os.path.basename(filename) - if basename in COMMENT_MAP: - return COMMENT_MAP[basename] - # Not a special file. Check the file extension. - ext = os.path.splitext(filename)[1] - if ext in COMMENT_MAP: - return COMMENT_MAP[ext] - # Not a know extension either, return None. - return None - -def process_file(filename): - """Processes the given file. - """ - cdescr = comment_for_filename(filename) - if cdescr is None: - # Either no filename extension, or not an extension that we - # know how to handle. - return - - dst_filename = filename + '.new' - src = open(filename) - dst = open(dst_filename, 'w') - try: - process_header(src, dst, cdescr) - except AlreadyDone: - print "+++ Already up to date: `%s'." % filename - dst.close() - os.unlink(dst_filename) - if filename in NO_COPYRIGHT: - # We expect the search for a copyright header to fail, and - # yet we found one... - print "Warning: `%s' should not be in NO_COPYRIGHT" % filename - return - except NotFound as inst: - dst.close() - os.unlink(dst_filename) - if not filename in NO_COPYRIGHT: - print "*** \033[31m%s\033[0m: %s" % (filename, inst) - return - - if filename in NO_COPYRIGHT: - # We expect the search for a copyright header to fail, and - # yet we found one... - print "Warning: `%s' should not be in NO_COPYRIGHT" % filename - - for line in src: - dst.write(line) - src.close() - dst.close() - os.rename(dst_filename, filename) +# +# Filenames are relative to the root directory. +EXCLUDE_LIST = ( + 'gdb/CONTRIBUTE', + 'gdb/gnulib' +) + +# Files which should not be modified, either because they are +# generated, non-FSF, or otherwise special (e.g. license text, +# or test cases which must be sensitive to line numbering). +# +# Matches any file or directory name anywhere. Use with caution. +# This is mostly for files that can be found in multiple directories. +# Eg: We want all files named COPYING to be left untouched. + +EXCLUDE_ALL_LIST = ( + "COPYING", "COPYING.LIB", "CVS", "configure", "copying.c", + "fdl.texi", "gpl.texi", "aclocal.m4", +) + +# The list of files to update by hand. +BY_HAND = ( + # These files are sensitive to line numbering. + "gdb/testsuite/gdb.base/step-line.inp", + "gdb/testsuite/gdb.base/step-line.c", +) + +# Files containing multiple copyright headers. This script is only +# fixing the first one it finds, so we need to finish the update +# by hand. +MULTIPLE_COPYRIGHT_HEADERS = ( + "gdb/doc/gdb.texinfo", + "gdb/doc/refcard.tex", + "gdb/gdbarch.sh", +) + +# The list of file which have a copyright, but not head by the FSF. +# Filenames are relative to the root directory. +NOT_FSF_LIST = ( + "gdb/exc_request.defs", + "gdb/gdbtk", + "gdb/testsuite/gdb.gdbtk/", + "sim/arm/armemu.h", "sim/arm/armos.c", "sim/arm/gdbhost.c", + "sim/arm/dbg_hif.h", "sim/arm/dbg_conf.h", "sim/arm/communicate.h", + "sim/arm/armos.h", "sim/arm/armcopro.c", "sim/arm/armemu.c", + "sim/arm/kid.c", "sim/arm/thumbemu.c", "sim/arm/armdefs.h", + "sim/arm/armopts.h", "sim/arm/dbg_cp.h", "sim/arm/dbg_rdi.h", + "sim/arm/parent.c", "sim/arm/armsupp.c", "sim/arm/armrdi.c", + "sim/arm/bag.c", "sim/arm/armvirt.c", "sim/arm/main.c", "sim/arm/bag.h", + "sim/arm/communicate.c", "sim/arm/gdbhost.h", "sim/arm/armfpe.h", + "sim/arm/arminit.c", + "sim/common/cgen-fpu.c", "sim/common/cgen-fpu.h", + "sim/common/cgen-accfp.c", + "sim/erc32/sis.h", "sim/erc32/erc32.c", "sim/erc32/func.c", + "sim/erc32/float.c", "sim/erc32/interf.c", "sim/erc32/sis.c", + "sim/erc32/exec.c", + "sim/mips/m16run.c", "sim/mips/sim-main.c", + "sim/moxie/moxie-gdb.dts", + # Not a single file in sim/ppc/ appears to be copyright FSF :-(. + "sim/ppc/filter.h", "sim/ppc/gen-support.h", "sim/ppc/ld-insn.h", + "sim/ppc/hw_sem.c", "sim/ppc/hw_disk.c", "sim/ppc/idecode_branch.h", + "sim/ppc/sim-endian.h", "sim/ppc/table.c", "sim/ppc/hw_core.c", + "sim/ppc/gen-support.c", "sim/ppc/gen-semantics.h", "sim/ppc/cpu.h", + "sim/ppc/sim_callbacks.h", "sim/ppc/RUN", "sim/ppc/Makefile.in", + "sim/ppc/emul_chirp.c", "sim/ppc/hw_nvram.c", "sim/ppc/dc-test.01", + "sim/ppc/hw_phb.c", "sim/ppc/hw_eeprom.c", "sim/ppc/bits.h", + "sim/ppc/hw_vm.c", "sim/ppc/cap.h", "sim/ppc/os_emul.h", + "sim/ppc/options.h", "sim/ppc/gen-idecode.c", "sim/ppc/filter.c", + "sim/ppc/corefile-n.h", "sim/ppc/std-config.h", "sim/ppc/ld-decode.h", + "sim/ppc/filter_filename.h", "sim/ppc/hw_shm.c", + "sim/ppc/pk_disklabel.c", "sim/ppc/dc-simple", "sim/ppc/misc.h", + "sim/ppc/device_table.h", "sim/ppc/ld-insn.c", "sim/ppc/inline.c", + "sim/ppc/emul_bugapi.h", "sim/ppc/hw_cpu.h", "sim/ppc/debug.h", + "sim/ppc/hw_ide.c", "sim/ppc/debug.c", "sim/ppc/gen-itable.h", + "sim/ppc/interrupts.c", "sim/ppc/hw_glue.c", "sim/ppc/emul_unix.c", + "sim/ppc/sim_calls.c", "sim/ppc/dc-complex", "sim/ppc/ld-cache.c", + "sim/ppc/registers.h", "sim/ppc/dc-test.02", "sim/ppc/options.c", + "sim/ppc/igen.h", "sim/ppc/registers.c", "sim/ppc/device.h", + "sim/ppc/emul_chirp.h", "sim/ppc/hw_register.c", "sim/ppc/hw_init.c", + "sim/ppc/sim-endian-n.h", "sim/ppc/filter_filename.c", + "sim/ppc/bits.c", "sim/ppc/idecode_fields.h", "sim/ppc/hw_memory.c", + "sim/ppc/misc.c", "sim/ppc/double.c", "sim/ppc/psim.h", + "sim/ppc/hw_trace.c", "sim/ppc/emul_netbsd.h", "sim/ppc/psim.c", + "sim/ppc/ppc-instructions", "sim/ppc/tree.h", "sim/ppc/README", + "sim/ppc/gen-icache.h", "sim/ppc/gen-model.h", "sim/ppc/ld-cache.h", + "sim/ppc/mon.c", "sim/ppc/corefile.h", "sim/ppc/vm.c", + "sim/ppc/INSTALL", "sim/ppc/gen-model.c", "sim/ppc/hw_cpu.c", + "sim/ppc/corefile.c", "sim/ppc/hw_opic.c", "sim/ppc/gen-icache.c", + "sim/ppc/events.h", "sim/ppc/os_emul.c", "sim/ppc/emul_generic.c", + "sim/ppc/main.c", "sim/ppc/hw_com.c", "sim/ppc/gen-semantics.c", + "sim/ppc/emul_bugapi.c", "sim/ppc/device.c", "sim/ppc/emul_generic.h", + "sim/ppc/tree.c", "sim/ppc/mon.h", "sim/ppc/interrupts.h", + "sim/ppc/cap.c", "sim/ppc/cpu.c", "sim/ppc/hw_phb.h", + "sim/ppc/device_table.c", "sim/ppc/lf.c", "sim/ppc/lf.c", + "sim/ppc/dc-stupid", "sim/ppc/hw_pal.c", "sim/ppc/ppc-spr-table", + "sim/ppc/emul_unix.h", "sim/ppc/words.h", "sim/ppc/basics.h", + "sim/ppc/hw_htab.c", "sim/ppc/lf.h", "sim/ppc/ld-decode.c", + "sim/ppc/sim-endian.c", "sim/ppc/gen-itable.c", + "sim/ppc/idecode_expression.h", "sim/ppc/table.h", "sim/ppc/dgen.c", + "sim/ppc/events.c", "sim/ppc/gen-idecode.h", "sim/ppc/emul_netbsd.c", + "sim/ppc/igen.c", "sim/ppc/vm_n.h", "sim/ppc/vm.h", + "sim/ppc/hw_iobus.c", "sim/ppc/inline.h", + "sim/testsuite/sim/bfin/s21.s", "sim/testsuite/sim/mips/mips32-dsp2.s", +) if __name__ == "__main__": - if not os.path.isfile("doc/gdb.texinfo"): - print "Error: This script must be called from the gdb directory." - for gdb_dir in ('.', '../sim', '../include/gdb'): - for root, dirs, files in os.walk(gdb_dir): - for filename in files: - fullpath = os.path.join(root, filename) - if fullpath.startswith('./'): - fullpath = fullpath[2:] - if filename not in EXCLUSION_LIST and fullpath not in BY_HAND: - # Paths that start with './' are ugly, so strip that. - # This also allows us to omit them in the NO_COPYRIGHT - # list... - process_file(fullpath) - print - print "\033[32mREMINDER: The following files must be updated by hand." \ - "\033[0m" - for filename in BY_HAND: - print " ", filename + main() diff --git a/contrib/gdb-7/gdb/corefile.c b/contrib/gdb-7/gdb/corefile.c index c07447b209..f195694012 100644 --- a/contrib/gdb-7/gdb/corefile.c +++ b/contrib/gdb-7/gdb/corefile.c @@ -1,7 +1,6 @@ /* Core dump and executable file functions above target vector, for GDB. - Copyright (C) 1986-1987, 1989, 1991-1994, 1996-2001, 2003, 2006-2012 - Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -34,6 +33,8 @@ #include "gdb_stat.h" #include "completer.h" #include "exceptions.h" +#include "observer.h" +#include "cli/cli-utils.h" /* Local function declarations. */ @@ -60,7 +61,7 @@ static int exec_file_hook_count = 0; /* Size of array. */ bfd *core_bfd = NULL; -/* corelow.c target (if included for this gdb target). */ +/* corelow.c target. It is never NULL after GDB initialization. */ struct target_ops *core_target; @@ -72,8 +73,7 @@ core_file_command (char *filename, int from_tty) { dont_repeat (); /* Either way, seems bogus. */ - if (core_target == NULL) - error (_("GDB can't read core files on this machine.")); + gdb_assert (core_target != NULL); if (!filename) (core_target->to_detach) (core_target, filename, from_tty); @@ -132,26 +132,9 @@ specify_exec_file_hook (void (*hook) (char *)) deprecated_exec_file_display_hook = hook; } -/* The exec file must be closed before running an inferior. - If it is needed again after the inferior dies, it must - be reopened. */ - -void -close_exec_file (void) -{ -#if 0 /* FIXME */ - if (exec_bfd) - bfd_tempclose (exec_bfd); -#endif -} - void reopen_exec_file (void) { -#if 0 /* FIXME */ - if (exec_bfd) - bfd_reopen (exec_bfd); -#else char *filename; int res; struct stat st; @@ -175,7 +158,6 @@ reopen_exec_file (void) bfd_cache_close_all (); do_cleanups (cleanups); -#endif } /* If we have both a core file and an exec file, @@ -200,8 +182,8 @@ validate_files (void) char * get_exec_file (int err) { - if (exec_bfd) - return bfd_get_filename (exec_bfd); + if (exec_filename) + return exec_filename; if (!err) return NULL; @@ -221,18 +203,18 @@ memory_error (int status, CORE_ADDR memaddr) bounds. */ throw_error (MEMORY_ERROR, _("Cannot access memory at address %s"), - paddress (target_gdbarch, memaddr)); + paddress (target_gdbarch (), memaddr)); else throw_error (MEMORY_ERROR, _("Error accessing memory address %s: %s."), - paddress (target_gdbarch, memaddr), + paddress (target_gdbarch (), memaddr), safe_strerror (status)); } /* Same as target_read_memory, but report an error if can't read. */ void -read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) +read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) { int status; @@ -244,7 +226,7 @@ read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) /* Same as target_read_stack, but report an error if can't read. */ void -read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len) +read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) { int status; @@ -349,7 +331,7 @@ read_memory_string (CORE_ADDR memaddr, char *buffer, int max_len) cnt = max_len - (cp - buffer); if (cnt > 8) cnt = 8; - read_memory (memaddr + (int) (cp - buffer), cp, cnt); + read_memory (memaddr + (int) (cp - buffer), (gdb_byte *) cp, cnt); for (i = 0; i < cnt && *cp; i++, cp++) ; /* null body */ @@ -371,7 +353,7 @@ read_memory_typed_address (CORE_ADDR addr, struct type *type) write. */ void write_memory (CORE_ADDR memaddr, - const bfd_byte *myaddr, int len) + const bfd_byte *myaddr, ssize_t len) { int status; @@ -380,6 +362,16 @@ write_memory (CORE_ADDR memaddr, memory_error (status, memaddr); } +/* Same as write_memory, but notify 'memory_changed' observers. */ + +void +write_memory_with_notification (CORE_ADDR memaddr, const bfd_byte *myaddr, + ssize_t len) +{ + write_memory (memaddr, myaddr, len); + observer_notify_memory_changed (current_inferior (), memaddr, len, myaddr); +} + /* Store VALUE at ADDR in the inferior as a LEN-byte unsigned integer. */ void @@ -428,12 +420,40 @@ static void set_gnutarget_command (char *ignore, int from_tty, struct cmd_list_element *c) { + char *gend = gnutarget_string + strlen (gnutarget_string); + + gend = remove_trailing_whitespace (gnutarget_string, gend); + *gend = '\0'; + if (strcmp (gnutarget_string, "auto") == 0) gnutarget = NULL; else gnutarget = gnutarget_string; } +/* A completion function for "set gnutarget". */ + +static VEC (char_ptr) * +complete_set_gnutarget (struct cmd_list_element *cmd, char *text, char *word) +{ + static const char **bfd_targets; + + if (bfd_targets == NULL) + { + int last; + + bfd_targets = bfd_target_list (); + for (last = 0; bfd_targets[last] != NULL; ++last) + ; + + bfd_targets = xrealloc (bfd_targets, (last + 2) * sizeof (const char **)); + bfd_targets[last] = "auto"; + bfd_targets[last + 1] = NULL; + } + + return complete_on_enum (bfd_targets, text, word); +} + /* Set the gnutarget. */ void set_gnutarget (char *newtarget) @@ -456,14 +476,17 @@ No arg means have no core file. This command has been superseded by the\n\ set_cmd_completer (c, filename_completer); - add_setshow_string_noescape_cmd ("gnutarget", class_files, - &gnutarget_string, _("\ + c = add_setshow_string_noescape_cmd ("gnutarget", class_files, + &gnutarget_string, _("\ Set the current BFD target."), _("\ Show the current BFD target."), _("\ Use `set gnutarget auto' to specify automatic detection."), - set_gnutarget_command, - show_gnutarget_string, - &setlist, &showlist); + set_gnutarget_command, + show_gnutarget_string, + &setlist, &showlist); + set_cmd_completer (c, complete_set_gnutarget); + + add_alias_cmd ("g", "gnutarget", class_files, 1, &setlist); if (getenv ("GNUTARGET")) set_gnutarget (getenv ("GNUTARGET")); diff --git a/contrib/gdb-7/gdb/corelow.c b/contrib/gdb-7/gdb/corelow.c index bbfb8ee51f..a98ae548fe 100644 --- a/contrib/gdb-7/gdb/corelow.c +++ b/contrib/gdb-7/gdb/corelow.c @@ -1,7 +1,6 @@ /* Core dump and executable file functions below target vector, for GDB. - Copyright (C) 1986-1987, 1989, 1991-2001, 2003-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -46,8 +45,7 @@ #include "filenames.h" #include "progspace.h" #include "objfiles.h" -#include "wrapper.h" - +#include "gdb_bfd.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 @@ -77,9 +75,6 @@ struct gdbarch *core_gdbarch = NULL; unix child targets. */ static struct target_section_table *core_data; -/* True if we needed to fake the pid of the loaded core inferior. */ -static int core_has_fake_pid = 0; - static void core_files_info (struct target_ops *); static struct core_fns *sniff_core_bfd (bfd *); @@ -131,8 +126,7 @@ default_core_sniffer (struct core_fns *our_fns, bfd *abfd) } /* Walk through the list of core functions to find a set that can - handle the core file open on ABFD. Default to the first one in the - list if nothing matches. Returns pointer to set that is + handle the core file open on ABFD. Returns pointer to set that is selected. */ static struct core_fns * @@ -161,15 +155,9 @@ sniff_core_bfd (bfd *abfd) bfd_get_filename (abfd), matches); } else if (matches == 0) - { - warning (_("\"%s\": no core file handler " - "recognizes format, using default"), - bfd_get_filename (abfd)); - } - if (yummy == NULL) - { - yummy = core_file_fns; - } + error (_("\"%s\": no core file handler recognizes format"), + bfd_get_filename (abfd)); + return (yummy); } @@ -206,27 +194,26 @@ gdb_check_format (bfd *abfd) static void core_close (int quitting) { - char *name; - if (core_bfd) { int pid = ptid_get_pid (inferior_ptid); inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */ - exit_inferior_silent (pid); + if (pid != 0) + exit_inferior_silent (pid); /* Clear out solib state while the bfd is still open. See comments in clear_solib in solib.c. */ clear_solib (); - xfree (core_data->sections); - xfree (core_data); - core_data = NULL; - core_has_fake_pid = 0; + if (core_data) + { + xfree (core_data->sections); + xfree (core_data); + core_data = NULL; + } - name = bfd_get_filename (core_bfd); - gdb_bfd_close_or_warn (core_bfd); - xfree (name); + gdb_bfd_unref (core_bfd); core_bfd = NULL; } core_vec = NULL; @@ -249,6 +236,8 @@ add_to_thread_list (bfd *abfd, asection *asect, void *reg_sect_arg) int core_tid; int pid, lwpid; asection *reg_sect = (asection *) reg_sect_arg; + int fake_pid_p = 0; + struct inferior *inf; if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0) return; @@ -258,14 +247,18 @@ add_to_thread_list (bfd *abfd, asection *asect, void *reg_sect_arg) pid = bfd_core_file_pid (core_bfd); if (pid == 0) { - core_has_fake_pid = 1; + fake_pid_p = 1; pid = CORELOW_PID; } lwpid = core_tid; - if (current_inferior ()->pid == 0) - inferior_appeared (current_inferior (), pid); + inf = current_inferior (); + if (inf->pid == 0) + { + inferior_appeared (inf, pid); + inf->fake_pid_p = fake_pid_p; + } ptid = ptid_build (pid, lwpid, 0); @@ -290,6 +283,7 @@ core_open (char *filename, int from_tty) bfd *temp_bfd; int scratch_chan; int flags; + volatile struct gdb_exception except; target_preopen (from_tty); if (!filename) @@ -321,9 +315,9 @@ core_open (char *filename, int from_tty) if (scratch_chan < 0) perror_with_name (filename); - temp_bfd = bfd_fopen (filename, gnutarget, - write_files ? FOPEN_RUB : FOPEN_RB, - scratch_chan); + temp_bfd = gdb_bfd_fopen (filename, gnutarget, + write_files ? FOPEN_RUB : FOPEN_RB, + scratch_chan); if (temp_bfd == NULL) perror_with_name (filename); @@ -334,7 +328,7 @@ core_open (char *filename, int from_tty) /* FIXME: should be checking for errors from bfd_close (for one thing, on error it does not free all the storage associated with the bfd). */ - make_cleanup_bfd_close (temp_bfd); + make_cleanup_bfd_unref (temp_bfd); error (_("\"%s\" is not a core dump: %s"), filename, bfd_errmsg (bfd_get_error ())); } @@ -342,17 +336,11 @@ core_open (char *filename, int from_tty) /* Looks semi-reasonable. Toss the old core file and work on the new. */ - discard_cleanups (old_chain); /* Don't free filename any more */ + do_cleanups (old_chain); unpush_target (&core_ops); core_bfd = temp_bfd; old_chain = make_cleanup (core_close_cleanup, 0 /*ignore*/); - /* FIXME: kettenis/20031023: This is very dangerous. The - CORE_GDBARCH that results from this call may very well be - different from CURRENT_GDBARCH. However, its methods may only - work if it is selected as the current architecture, because they - rely on swapped data (see gdbarch.c). We should get rid of that - swapped data. */ core_gdbarch = gdbarch_from_bfd (core_bfd); /* Find a suitable core file handler to munch on core_bfd */ @@ -386,7 +374,6 @@ core_open (char *filename, int from_tty) init_thread_list (); inferior_ptid = null_ptid; - core_has_fake_pid = 0; /* Need to flush the register cache (and the frame cache) from a previous debug session. If inferior_ptid ends up the same as the @@ -428,7 +415,13 @@ core_open (char *filename, int from_tty) may be a thread_stratum target loaded on top of target core by now. The layer above should claim threads found in the BFD sections. */ - gdb_target_find_new_threads (); + TRY_CATCH (except, RETURN_MASK_ERROR) + { + target_find_new_threads (); + } + + if (except.reason < 0) + exception_print (gdb_stderr, except); p = bfd_core_file_failing_command (core_bfd); if (p) @@ -437,17 +430,20 @@ core_open (char *filename, int from_tty) siggy = bfd_core_file_failing_signal (core_bfd); if (siggy > 0) { - /* NOTE: target_signal_from_host() converts a target signal - value into gdb's internal signal value. Unfortunately gdb's - internal value is called ``target_signal'' and this function - got the name ..._from_host(). */ - enum target_signal sig = (core_gdbarch != NULL - ? gdbarch_target_signal_from_host (core_gdbarch, - siggy) - : target_signal_from_host (siggy)); + /* If we don't have a CORE_GDBARCH to work with, assume a native + core (map gdb_signal from host signals). If we do have + CORE_GDBARCH to work with, but no gdb_signal_from_target + implementation for that gdbarch, as a fallback measure, + assume the host signal mapping. It'll be correct for native + cores, but most likely incorrect for cross-cores. */ + enum gdb_signal sig = (core_gdbarch != NULL + && gdbarch_gdb_signal_from_target_p (core_gdbarch) + ? gdbarch_gdb_signal_from_target (core_gdbarch, + siggy) + : gdb_signal_from_host (siggy)); printf_filtered (_("Program terminated with signal %d, %s.\n"), - siggy, target_signal_to_string (sig)); + siggy, gdb_signal_to_string (sig)); } /* Fetch all registers from core file. */ @@ -657,6 +653,35 @@ add_to_spuid_list (bfd *abfd, asection *asect, void *list_p) list->pos += 4; } +/* Read siginfo data from the core, if possible. Returns -1 on + failure. Otherwise, returns the number of bytes read. ABFD is the + core file's BFD; READBUF, OFFSET, and LEN are all as specified by + the to_xfer_partial interface. */ + +static LONGEST +get_core_siginfo (bfd *abfd, gdb_byte *readbuf, ULONGEST offset, LONGEST len) +{ + asection *section; + char *section_name; + const char *name = ".note.linuxcore.siginfo"; + + if (ptid_get_lwp (inferior_ptid)) + section_name = xstrprintf ("%s/%ld", name, + ptid_get_lwp (inferior_ptid)); + else + section_name = xstrdup (name); + + section = bfd_get_section_by_name (abfd, section_name); + xfree (section_name); + if (section == NULL) + return -1; + + if (!bfd_get_section_contents (abfd, section, readbuf, offset, len)) + return -1; + + return len; +} + static LONGEST core_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, @@ -795,6 +820,11 @@ core_xfer_partial (struct target_ops *ops, enum target_object object, } return -1; + case TARGET_OBJECT_SIGNAL_INFO: + if (readbuf) + return get_core_siginfo (core_bfd, readbuf, offset, len); + return -1; + default: if (ops->beneath != NULL) return ops->beneath->to_xfer_partial (ops->beneath, object, @@ -847,6 +877,7 @@ static char * core_pid_to_str (struct target_ops *ops, ptid_t ptid) { static char buf[64]; + struct inferior *inf; int pid; /* The preferred way is to have a gdbarch/OS specific @@ -865,7 +896,8 @@ core_pid_to_str (struct target_ops *ops, ptid_t ptid) /* Otherwise, this isn't a "threaded" core -- use the PID field, but only if it isn't a fake PID. */ - if (!core_has_fake_pid) + inf = find_inferior_pid (ptid_get_pid (ptid)); + if (inf != NULL && !inf->fake_pid_p) return normal_pid_to_str (ptid); /* No luck. We simply don't have a valid PID to print. */ @@ -891,6 +923,19 @@ core_has_registers (struct target_ops *ops) return (core_bfd != NULL); } +/* Implement the to_info_proc method. */ + +static void +core_info_proc (struct target_ops *ops, char *args, enum info_proc_what request) +{ + struct gdbarch *gdbarch = get_current_arch (); + + /* Since this is the core file target, call the 'core_info_proc' + method on gdbarch, not 'info_proc'. */ + if (gdbarch_core_info_proc_p (gdbarch)) + gdbarch_core_info_proc (gdbarch, args, request); +} + /* Fill in core_ops with its defined operations and properties. */ static void @@ -917,6 +962,7 @@ init_core_ops (void) core_ops.to_has_memory = core_has_memory; core_ops.to_has_stack = core_has_stack; core_ops.to_has_registers = core_has_registers; + core_ops.to_info_proc = core_info_proc; core_ops.to_magic = OPS_MAGIC; if (core_target) diff --git a/contrib/gdb-7/gdb/cp-abi.c b/contrib/gdb-7/gdb/cp-abi.c index cdc4a139cf..366ba30ecf 100644 --- a/contrib/gdb-7/gdb/cp-abi.c +++ b/contrib/gdb-7/gdb/cp-abi.c @@ -1,6 +1,6 @@ /* Generic code for supporting multiple C++ ABI's - Copyright (C) 2001-2003, 2005-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -111,7 +111,7 @@ value_rtti_type (struct value *v, int *full, int *top, int *using_enc) { struct type *ret = NULL; - struct gdb_exception e; + volatile struct gdb_exception e; if ((current_cp_abi.rtti_type) == NULL) return NULL; @@ -169,6 +169,16 @@ cplus_method_ptr_to_value (struct value **this_p, return (*current_cp_abi.method_ptr_to_value) (this_p, method_ptr); } +/* See cp-abi.h. */ + +void +cplus_print_vtable (struct value *value) +{ + if (current_cp_abi.print_vtable == NULL) + error (_("GDB cannot print the vtable on this target")); + (*current_cp_abi.print_vtable) (value); +} + int cp_pass_by_reference (struct type *type) { @@ -304,6 +314,27 @@ set_cp_abi_cmd (char *args, int from_tty) error (_("Could not find \"%s\" in ABI list"), args); } +/* A completion function for "set cp-abi". */ + +static VEC (char_ptr) * +cp_abi_completer (struct cmd_list_element *ignore, + char *text, char *word) +{ + static const char **cp_abi_names; + + if (cp_abi_names == NULL) + { + int i; + + cp_abi_names = XNEWVEC (const char *, num_cp_abis + 1); + for (i = 0; i < num_cp_abis; ++i) + cp_abi_names[i] = cp_abis[i]->shortname; + cp_abi_names[i] = NULL; + } + + return complete_on_enum (cp_abi_names, text, word); +} + /* Show the currently selected C++ ABI. */ static void @@ -324,13 +355,16 @@ extern initialize_file_ftype _initialize_cp_abi; /* -Wmissing-prototypes */ void _initialize_cp_abi (void) { + struct cmd_list_element *c; + register_cp_abi (&auto_cp_abi); switch_to_cp_abi ("auto"); - add_cmd ("cp-abi", class_obscure, set_cp_abi_cmd, _("\ + c = add_cmd ("cp-abi", class_obscure, set_cp_abi_cmd, _("\ Set the ABI used for inspecting C++ objects.\n\ \"set cp-abi\" with no arguments will list the available ABIs."), - &setlist); + &setlist); + set_cmd_completer (c, cp_abi_completer); add_cmd ("cp-abi", class_obscure, show_cp_abi_cmd, _("Show the ABI used for inspecting C++ objects."), diff --git a/contrib/gdb-7/gdb/cp-abi.h b/contrib/gdb-7/gdb/cp-abi.h index 0f24e9a975..96e9aeac22 100644 --- a/contrib/gdb-7/gdb/cp-abi.h +++ b/contrib/gdb-7/gdb/cp-abi.h @@ -3,7 +3,7 @@ Contributed by Daniel Berlin - Copyright (C) 2001, 2005-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -173,6 +173,11 @@ struct value *cplus_method_ptr_to_value (struct value **this_p, void cplus_make_method_ptr (struct type *type, gdb_byte *CONTENTS, CORE_ADDR address, int is_virtual); +/* Print the vtable for VALUE, if there is one. If there is no + vtable, print a message, but do not throw. */ + +void cplus_print_vtable (struct value *value); + /* Determine if we are currently in a C++ thunk. If so, get the address of the routine we are thunking to and continue to there instead. */ @@ -213,6 +218,7 @@ struct cp_abi_ops CORE_ADDR, int); struct value * (*method_ptr_to_value) (struct value **, struct value *); + void (*print_vtable) (struct value *); CORE_ADDR (*skip_trampoline) (struct frame_info *, CORE_ADDR); int (*pass_by_reference) (struct type *type); }; diff --git a/contrib/gdb-7/gdb/cp-name-parser.y b/contrib/gdb-7/gdb/cp-name-parser.y index 8b4a1b946c..01a1fa4967 100644 --- a/contrib/gdb-7/gdb/cp-name-parser.y +++ b/contrib/gdb-7/gdb/cp-name-parser.y @@ -1,6 +1,6 @@ /* YACC parser for C++ names, for GDB. - Copyright (C) 2003-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. Parts of the lexer are based on c-exp.y from GDB. @@ -170,6 +170,12 @@ static struct demangle_component *d_binary (const char *, #define yygindex cpname_yygindex #define yytable cpname_yytable #define yycheck cpname_yycheck +#define yyss cpname_yyss +#define yysslim cpname_yysslim +#define yyssp cpname_yyssp +#define yystacksize cpname_yystacksize +#define yyvs cpname_yyvs +#define yyvsp cpname_yyvsp int yyparse (void); static int yylex (void); @@ -188,7 +194,11 @@ fill_comp (enum demangle_component_type d_type, struct demangle_component *lhs, struct demangle_component *rhs) { struct demangle_component *ret = d_grab (); - cplus_demangle_fill_component (ret, d_type, lhs, rhs); + int i; + + i = cplus_demangle_fill_component (ret, d_type, lhs, rhs); + gdb_assert (i); + return ret; } @@ -204,7 +214,11 @@ static struct demangle_component * make_operator (const char *name, int args) { struct demangle_component *ret = d_grab (); - cplus_demangle_fill_operator (ret, name, args); + int i; + + i = cplus_demangle_fill_operator (ret, name, args); + gdb_assert (i); + return ret; } @@ -212,7 +226,11 @@ static struct demangle_component * make_dtor (enum gnu_v3_dtor_kinds kind, struct demangle_component *name) { struct demangle_component *ret = d_grab (); - cplus_demangle_fill_dtor (ret, kind, name); + int i; + + i = cplus_demangle_fill_dtor (ret, kind, name); + gdb_assert (i); + return ret; } @@ -220,7 +238,11 @@ static struct demangle_component * make_builtin_type (const char *name) { struct demangle_component *ret = d_grab (); - cplus_demangle_fill_builtin_type (ret, name); + int i; + + i = cplus_demangle_fill_builtin_type (ret, name); + gdb_assert (i); + return ret; } @@ -228,7 +250,11 @@ static struct demangle_component * make_name (const char *name, int len) { struct demangle_component *ret = d_grab (); - cplus_demangle_fill_name (ret, name, len); + int i; + + i = cplus_demangle_fill_name (ret, name, len); + gdb_assert (i); + return ret; } @@ -420,13 +446,29 @@ demangler_special ; operator : OPERATOR NEW - { $$ = make_operator ("new", 1); } + { + /* Match the whitespacing of cplus_demangle_operators. + It would abort on unrecognized string otherwise. */ + $$ = make_operator ("new", 3); + } | OPERATOR DELETE - { $$ = make_operator ("delete", 1); } + { + /* Match the whitespacing of cplus_demangle_operators. + It would abort on unrecognized string otherwise. */ + $$ = make_operator ("delete ", 1); + } | OPERATOR NEW '[' ']' - { $$ = make_operator ("new[]", 1); } + { + /* Match the whitespacing of cplus_demangle_operators. + It would abort on unrecognized string otherwise. */ + $$ = make_operator ("new[]", 3); + } | OPERATOR DELETE '[' ']' - { $$ = make_operator ("delete[]", 1); } + { + /* Match the whitespacing of cplus_demangle_operators. + It would abort on unrecognized string otherwise. */ + $$ = make_operator ("delete[] ", 1); + } | OPERATOR '+' { $$ = make_operator ("+", 2); } | OPERATOR '-' @@ -1157,7 +1199,11 @@ exp : FLOAT ; exp : SIZEOF '(' type ')' %prec UNARY - { $$ = d_unary ("sizeof", $3); } + { + /* Match the whitespacing of cplus_demangle_operators. + It would abort on unrecognized string otherwise. */ + $$ = d_unary ("sizeof ", $3); + } ; /* C++. */ diff --git a/contrib/gdb-7/gdb/cp-namespace.c b/contrib/gdb-7/gdb/cp-namespace.c index 170dd5f82f..8f8dab653b 100644 --- a/contrib/gdb-7/gdb/cp-namespace.c +++ b/contrib/gdb-7/gdb/cp-namespace.c @@ -1,5 +1,5 @@ /* Helper routines for C++ support in GDB. - Copyright (C) 2003-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. Contributed by David Carlton and by Kealia, Inc. @@ -42,7 +42,8 @@ static struct symbol *lookup_namespace_scope (const char *name, static struct symbol *lookup_symbol_file (const char *name, const struct block *block, const domain_enum domain, - int anonymous_namespace); + int anonymous_namespace, + int search); static struct type *cp_lookup_transparent_type_loop (const char *name, const char *scope, @@ -95,7 +96,7 @@ cp_scan_for_anonymous_namespaces (const struct symbol *const symbol, 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 (dest, src, NULL, NULL, NULL, + cp_add_using_directive (dest, src, NULL, NULL, NULL, 1, &objfile->objfile_obstack); } /* The "+ 2" is for the "::". */ @@ -116,9 +117,10 @@ cp_scan_for_anonymous_namespaces (const struct symbol *const symbol, in the current scope. If ALIAS is NULL then the namespace is known by its original name. DECLARATION is the name if the imported varable if this is a declaration import (Eg. using A::x), otherwise - it is NULL. EXCLUDES is a list of names not to import from an imported - module or NULL. The arguments are copied into newly allocated memory so - they can be temporaries. For EXCLUDES the VEC pointers are copied but the + it is NULL. EXCLUDES is a list of names not to import from an + imported module or NULL. If COPY_NAMES is non-zero, then the + arguments are copied into newly allocated memory so they can be + temporaries. For EXCLUDES the VEC pointers are copied but the pointed to characters are not copied. */ void @@ -127,6 +129,7 @@ cp_add_using_directive (const char *dest, const char *alias, const char *declaration, VEC (const_char_ptr) *excludes, + int copy_names, struct obstack *obstack) { struct using_direct *current; @@ -172,15 +175,27 @@ cp_add_using_directive (const char *dest, * sizeof (*new->excludes)))); memset (new, 0, sizeof (*new)); - new->import_src = obsavestring (src, strlen (src), obstack); - new->import_dest = obsavestring (dest, strlen (dest), obstack); + if (copy_names) + { + new->import_src = obstack_copy0 (obstack, src, strlen (src)); + new->import_dest = obstack_copy0 (obstack, dest, strlen (dest)); + } + else + { + new->import_src = src; + new->import_dest = dest; + } - if (alias != NULL) - new->alias = obsavestring (alias, strlen (alias), obstack); + if (alias != NULL && copy_names) + new->alias = obstack_copy0 (obstack, alias, strlen (alias)); + else + new->alias = alias; - if (declaration != NULL) - new->declaration = obsavestring (declaration, strlen (declaration), - obstack); + if (declaration != NULL && copy_names) + new->declaration = obstack_copy0 (obstack, + declaration, strlen (declaration)); + else + new->declaration = declaration; memcpy (new->excludes, VEC_address (const_char_ptr, excludes), VEC_length (const_char_ptr, excludes) * sizeof (*new->excludes)); @@ -190,44 +205,6 @@ cp_add_using_directive (const char *dest, using_directives = new; } -/* Record the namespace that the function defined by SYMBOL was - defined in, if necessary. BLOCK is the associated block; use - OBSTACK for allocation. */ - -void -cp_set_block_scope (const struct symbol *symbol, - struct block *block, - struct obstack *obstack, - const char *processing_current_prefix, - int processing_has_namespace_info) -{ - if (processing_has_namespace_info) - { - block_set_scope - (block, obsavestring (processing_current_prefix, - strlen (processing_current_prefix), - obstack), - obstack); - } - else if (SYMBOL_DEMANGLED_NAME (symbol) != NULL) - { - /* Try to figure out the appropriate namespace from the - demangled name. */ - - /* FIXME: carlton/2003-04-15: If the function in question is - a method of a class, the name will actually include the - name of the class as well. This should be harmless, but - is a little unfortunate. */ - - const char *name = SYMBOL_DEMANGLED_NAME (symbol); - unsigned int prefix_len = cp_entire_prefix_len (name); - - block_set_scope (block, - obsavestring (name, prefix_len, obstack), - obstack); - } -} - /* Test whether or not NAMESPACE looks like it mentions an anonymous namespace; return nonzero if so. */ @@ -264,17 +241,18 @@ cp_lookup_symbol_nonlocal (const char *name, } /* Look up NAME in the C++ namespace NAMESPACE. Other arguments are - as in cp_lookup_symbol_nonlocal. */ + as in cp_lookup_symbol_nonlocal. If SEARCH is non-zero, search + through base classes for a matching symbol. */ static struct symbol * cp_lookup_symbol_in_namespace (const char *namespace, const char *name, const struct block *block, - const domain_enum domain) + const domain_enum domain, int search) { if (namespace[0] == '\0') { - return lookup_symbol_file (name, block, domain, 0); + return lookup_symbol_file (name, block, domain, 0, search); } else { @@ -285,7 +263,7 @@ cp_lookup_symbol_in_namespace (const char *namespace, strcat (concatenated_name, "::"); strcat (concatenated_name, name); return lookup_symbol_file (concatenated_name, block, domain, - cp_is_anonymous (namespace)); + cp_is_anonymous (namespace), search); } } @@ -341,7 +319,7 @@ cp_lookup_symbol_imports (const char *scope, /* First, try to find the symbol in the given namespace. */ if (!declaration_only) sym = cp_lookup_symbol_in_namespace (scope, name, - block, domain); + block, domain, 1); if (sym != NULL) return sym; @@ -385,7 +363,7 @@ cp_lookup_symbol_imports (const char *scope, ? current->alias : current->declaration) == 0) sym = cp_lookup_symbol_in_namespace (current->import_src, current->declaration, - block, domain); + block, domain, 1); /* If this is a DECLARATION_ONLY search or a symbol was found or this import statement was an import declaration, the @@ -419,7 +397,7 @@ cp_lookup_symbol_imports (const char *scope, { sym = cp_lookup_symbol_in_namespace (scope, current->import_src, - block, domain); + block, domain, 1); } else if (current->alias == NULL) { @@ -473,10 +451,6 @@ cp_lookup_symbol_imports_or_template (const char *scope, if (function != NULL && SYMBOL_LANGUAGE (function) == language_cplus) { - int i; - struct cplus_specific *cps - = function->ginfo.language_specific.cplus_specific; - /* Search the function's template parameters. */ if (SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (function)) { @@ -550,7 +524,7 @@ cp_lookup_symbol_namespace (const char *scope, /* First, try to find the symbol in the given namespace. */ sym = cp_lookup_symbol_in_namespace (scope, name, - block, domain); + block, domain, 1); if (sym != NULL) return sym; @@ -621,19 +595,20 @@ lookup_namespace_scope (const char *name, strncpy (namespace, scope, scope_len); namespace[scope_len] = '\0'; return cp_lookup_symbol_in_namespace (namespace, name, - block, domain); + block, domain, 1); } /* Look up NAME in BLOCK's static block and in global blocks. If ANONYMOUS_NAMESPACE is nonzero, the symbol in question is located - within an anonymous namespace. Other arguments are as in + within an anonymous namespace. If SEARCH is non-zero, search through + base classes for a matching symbol. Other arguments are as in cp_lookup_symbol_nonlocal. */ static struct symbol * lookup_symbol_file (const char *name, const struct block *block, const domain_enum domain, - int anonymous_namespace) + int anonymous_namespace, int search) { struct symbol *sym = NULL; @@ -657,17 +632,142 @@ lookup_symbol_file (const char *name, sym = lookup_symbol_global (name, block, domain); } + if (sym != NULL) + return sym; + + if (search) + { + char *klass, *nested; + unsigned int prefix_len; + struct cleanup *cleanup; + struct symbol *klass_sym; + + /* A simple lookup failed. Check if the symbol was defined in + a base class. */ + + cleanup = make_cleanup (null_cleanup, NULL); + + /* Find the name of the class and the name of the method, + variable, etc. */ + prefix_len = cp_entire_prefix_len (name); + + /* If no prefix was found, search "this". */ + if (prefix_len == 0) + { + struct type *type; + struct symbol *this; + + this = lookup_language_this (language_def (language_cplus), block); + if (this == NULL) + { + do_cleanups (cleanup); + return NULL; + } + + type = check_typedef (TYPE_TARGET_TYPE (SYMBOL_TYPE (this))); + klass = xstrdup (TYPE_NAME (type)); + nested = xstrdup (name); + } + else + { + /* The class name is everything up to and including PREFIX_LEN. */ + klass = savestring (name, prefix_len); + + /* The rest of the name is everything else past the initial scope + operator. */ + nested = xstrdup (name + prefix_len + 2); + } + + /* Add cleanups to free memory for these strings. */ + make_cleanup (xfree, klass); + make_cleanup (xfree, nested); + + /* Lookup a class named KLASS. If none is found, there is nothing + more that can be done. */ + klass_sym = lookup_symbol_global (klass, block, domain); + if (klass_sym == NULL) + { + do_cleanups (cleanup); + return NULL; + } + + /* Look for a symbol named NESTED in this class. */ + sym = cp_lookup_nested_symbol (SYMBOL_TYPE (klass_sym), nested, block); + do_cleanups (cleanup); + } + + return sym; +} + +/* Search through the base classes of PARENT_TYPE for a symbol named + NAME in block BLOCK. */ + +static struct symbol * +find_symbol_in_baseclass (struct type *parent_type, const char *name, + const struct block *block) +{ + int i; + struct symbol *sym; + struct cleanup *cleanup; + char *concatenated_name; + + sym = NULL; + concatenated_name = NULL; + cleanup = make_cleanup (free_current_contents, &concatenated_name); + for (i = 0; i < TYPE_N_BASECLASSES (parent_type); ++i) + { + size_t len; + struct type *base_type = TYPE_BASECLASS (parent_type, i); + const char *base_name = TYPE_BASECLASS_NAME (parent_type, i); + + if (base_name == NULL) + continue; + + /* Search this particular base class. */ + sym = cp_lookup_symbol_in_namespace (base_name, name, block, + VAR_DOMAIN, 0); + if (sym != NULL) + break; + + /* Now search all static file-level symbols. We have to do this for + things like typedefs in the class. First search in this symtab, + what we want is possibly there. */ + len = strlen (base_name) + 2 + strlen (name) + 1; + concatenated_name = xrealloc (concatenated_name, len); + xsnprintf (concatenated_name, len, "%s::%s", base_name, name); + sym = lookup_symbol_static (concatenated_name, block, VAR_DOMAIN); + if (sym != NULL) + break; + + /* Nope. We now have to search all static blocks in all objfiles, + even if block != NULL, because there's no guarantees as to which + symtab the symbol we want is in. */ + sym = lookup_static_symbol_aux (concatenated_name, VAR_DOMAIN); + if (sym != NULL) + break; + + /* If this class has base classes, search them next. */ + CHECK_TYPEDEF (base_type); + if (TYPE_N_BASECLASSES (base_type) > 0) + { + sym = find_symbol_in_baseclass (base_type, name, block); + if (sym != NULL) + break; + } + } + + do_cleanups (cleanup); return sym; } -/* Look up a type named NESTED_NAME that is nested inside the C++ +/* Look up a symbol named NESTED_NAME that is nested inside the C++ class or namespace given by PARENT_TYPE, from within the context given by BLOCK. Return NULL if there is no such nested type. */ -struct type * -cp_lookup_nested_type (struct type *parent_type, - const char *nested_name, - const struct block *block) +struct symbol * +cp_lookup_nested_symbol (struct type *parent_type, + const char *nested_name, + const struct block *block) { /* type_name_no_tag_required provides better error reporting using the original type. */ @@ -688,35 +788,42 @@ cp_lookup_nested_type (struct type *parent_type, just like members of namespaces; in particular, lookup_symbol_namespace works when looking them up. */ + int size; const char *parent_name = type_name_no_tag_or_error (saved_parent_type); struct symbol *sym = cp_lookup_symbol_in_namespace (parent_name, nested_name, - block, VAR_DOMAIN); + block, VAR_DOMAIN, 0); char *concatenated_name; - if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF) - return SYMBOL_TYPE (sym); + if (sym != NULL) + return sym; - /* Now search all static file-level symbols. Not strictly - correct, but more useful than an error. We do not try to + /* Now search all static file-level symbols. We have to do this + for things like typedefs in the class. We do not try to guess any imported namespace as even the fully specified - namespace seach is is already not C++ compliant and more + namespace search is already not C++ compliant and more assumptions could make it too magic. */ - concatenated_name = alloca (strlen (parent_name) + 2 - + strlen (nested_name) + 1); - sprintf (concatenated_name, "%s::%s", + size = strlen (parent_name) + 2 + strlen (nested_name) + 1; + concatenated_name = alloca (size); + xsnprintf (concatenated_name, size, "%s::%s", parent_name, nested_name); - sym = lookup_static_symbol_aux (concatenated_name, - VAR_DOMAIN); - if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF) - return SYMBOL_TYPE (sym); + sym = lookup_static_symbol_aux (concatenated_name, VAR_DOMAIN); + if (sym != NULL) + return sym; - return NULL; + /* If no matching symbols were found, try searching any + base classes. */ + return find_symbol_in_baseclass (parent_type, nested_name, block); } + + case TYPE_CODE_FUNC: + case TYPE_CODE_METHOD: + return NULL; + default: internal_error (__FILE__, __LINE__, - _("cp_lookup_nested_type called " + _("cp_lookup_nested_symbol called " "on a non-aggregate type.")); } } diff --git a/contrib/gdb-7/gdb/cp-support.c b/contrib/gdb-7/gdb/cp-support.c index 8cea2c5ce3..22e8fc4c13 100644 --- a/contrib/gdb-7/gdb/cp-support.c +++ b/contrib/gdb-7/gdb/cp-support.c @@ -1,5 +1,5 @@ /* Helper routines for C++ support in GDB. - Copyright (C) 2002-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. Contributed by MontaVista Software. @@ -34,6 +34,7 @@ #include "exceptions.h" #include "expression.h" #include "value.h" +#include "cp-abi.h" #include "safe-ctype.h" @@ -72,19 +73,6 @@ struct cmd_list_element *maint_cplus_cmd_list = NULL; static void maint_cplus_command (char *arg, int from_tty); static void first_component_command (char *arg, int from_tty); -/* Operator validation. - NOTE: Multi-byte operators (usually the assignment variety - operator) must appear before the single byte version, i.e., "+=" - before "+". */ -static const char *operator_tokens[] = - { - "++", "+=", "+", "->*", "->", "--", "-=", "-", "*=", "*", - "/=", "/", "%=", "%", "!=", "==", "!", "&&", "<<=", "<<", - ">>=", ">>", "<=", "<", ">=", ">", "~", "&=", "&", "|=", - "||", "|", "^=", "^", "=", "()", "[]", ",", "new", "delete" - /* new[] and delete[] require special whitespace handling */ - }; - /* A list of typedefs which should not be substituted by replace_typedefs. */ static const char * const ignore_typedefs[] = { @@ -93,7 +81,9 @@ static const char * const ignore_typedefs[] = static void replace_typedefs (struct demangle_parse_info *info, - struct demangle_component *ret_comp); + struct demangle_component *ret_comp, + canonicalization_ftype *finder, + void *data); /* A convenience function to copy STRING into OBSTACK, returning a pointer to the newly allocated string and saving the number of bytes saved in LEN. @@ -164,7 +154,9 @@ cp_already_canonical (const char *string) static int inspect_type (struct demangle_parse_info *info, - struct demangle_component *ret_comp) + struct demangle_component *ret_comp, + canonicalization_ftype *finder, + void *data) { int i; char *name; @@ -194,6 +186,20 @@ inspect_type (struct demangle_parse_info *info, { struct type *otype = SYMBOL_TYPE (sym); + if (finder != NULL) + { + const char *new_name = (*finder) (otype, data); + + if (new_name != NULL) + { + ret_comp->u.s_name.s = new_name; + ret_comp->u.s_name.len = strlen (new_name); + return 1; + } + + return 0; + } + /* If the type is a typedef, replace it. */ if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF) { @@ -261,7 +267,7 @@ inspect_type (struct demangle_parse_info *info, if the type is anonymous (that would lead to infinite looping). */ if (!is_anon) - replace_typedefs (info, ret_comp); + replace_typedefs (info, ret_comp, finder, data); } else { @@ -298,7 +304,9 @@ inspect_type (struct demangle_parse_info *info, static void replace_typedefs_qualified_name (struct demangle_parse_info *info, - struct demangle_component *ret_comp) + struct demangle_component *ret_comp, + canonicalization_ftype *finder, + void *data) { long len; char *name; @@ -322,7 +330,7 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info, new.type = DEMANGLE_COMPONENT_NAME; new.u.s_name.s = name; new.u.s_name.len = len; - if (inspect_type (info, &new)) + if (inspect_type (info, &new, finder, data)) { char *n, *s; long slen; @@ -356,7 +364,7 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info, /* The current node is not a name, so simply replace any typedefs in it. Then print it to the stream to continue checking for more typedefs in the tree. */ - replace_typedefs (info, d_left (comp)); + replace_typedefs (info, d_left (comp), finder, data); name = cp_comp_to_string (d_left (comp), 100); if (name == NULL) { @@ -367,6 +375,7 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info, fputs_unfiltered (name, buf); xfree (name); } + ui_file_write (buf, "::", 2); comp = d_right (comp); } @@ -386,10 +395,10 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info, ret_comp->type = DEMANGLE_COMPONENT_NAME; ret_comp->u.s_name.s = name; ret_comp->u.s_name.len = len; - inspect_type (info, ret_comp); + inspect_type (info, ret_comp, finder, data); } else - replace_typedefs (info, comp); + replace_typedefs (info, comp, finder, data); ui_file_delete (buf); } @@ -417,10 +426,48 @@ check_cv_qualifiers (struct demangle_component *ret_comp) static void replace_typedefs (struct demangle_parse_info *info, - struct demangle_component *ret_comp) + struct demangle_component *ret_comp, + canonicalization_ftype *finder, + void *data) { if (ret_comp) { + if (finder != NULL + && (ret_comp->type == DEMANGLE_COMPONENT_NAME + || ret_comp->type == DEMANGLE_COMPONENT_QUAL_NAME + || ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE + || ret_comp->type == DEMANGLE_COMPONENT_BUILTIN_TYPE)) + { + char *local_name = cp_comp_to_string (ret_comp, 10); + + if (local_name != NULL) + { + struct symbol *sym; + volatile struct gdb_exception except; + + sym = NULL; + TRY_CATCH (except, RETURN_MASK_ALL) + { + sym = lookup_symbol (local_name, 0, VAR_DOMAIN, 0); + } + xfree (local_name); + + if (except.reason >= 0 && sym != NULL) + { + struct type *otype = SYMBOL_TYPE (sym); + const char *new_name = (*finder) (otype, data); + + if (new_name != NULL) + { + ret_comp->type = DEMANGLE_COMPONENT_NAME; + ret_comp->u.s_name.s = new_name; + ret_comp->u.s_name.len = strlen (new_name); + return; + } + } + } + } + switch (ret_comp->type) { case DEMANGLE_COMPONENT_ARGLIST: @@ -431,23 +478,23 @@ replace_typedefs (struct demangle_parse_info *info, case DEMANGLE_COMPONENT_TEMPLATE: case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: case DEMANGLE_COMPONENT_TYPED_NAME: - replace_typedefs (info, d_left (ret_comp)); - replace_typedefs (info, d_right (ret_comp)); + replace_typedefs (info, d_left (ret_comp), finder, data); + replace_typedefs (info, d_right (ret_comp), finder, data); break; case DEMANGLE_COMPONENT_NAME: - inspect_type (info, ret_comp); + inspect_type (info, ret_comp, finder, data); break; case DEMANGLE_COMPONENT_QUAL_NAME: - replace_typedefs_qualified_name (info, ret_comp); + replace_typedefs_qualified_name (info, ret_comp, finder, data); break; case DEMANGLE_COMPONENT_LOCAL_NAME: case DEMANGLE_COMPONENT_CTOR: case DEMANGLE_COMPONENT_ARRAY_TYPE: case DEMANGLE_COMPONENT_PTRMEM_TYPE: - replace_typedefs (info, d_right (ret_comp)); + replace_typedefs (info, d_right (ret_comp), finder, data); break; case DEMANGLE_COMPONENT_CONST: @@ -458,7 +505,7 @@ replace_typedefs (struct demangle_parse_info *info, case DEMANGLE_COMPONENT_RESTRICT_THIS: case DEMANGLE_COMPONENT_POINTER: case DEMANGLE_COMPONENT_REFERENCE: - replace_typedefs (info, d_left (ret_comp)); + replace_typedefs (info, d_left (ret_comp), finder, data); break; default: @@ -470,10 +517,13 @@ replace_typedefs (struct demangle_parse_info *info, /* Parse STRING and convert it to canonical form, resolving any typedefs. If parsing fails, or if STRING is already canonical, return NULL. Otherwise return the canonical form. The return value is allocated via - xmalloc. */ + xmalloc. If FINDER is not NULL, then type components are passed to + FINDER to be looked up. DATA is passed verbatim to FINDER. */ char * -cp_canonicalize_string_no_typedefs (const char *string) +cp_canonicalize_string_full (const char *string, + canonicalization_ftype *finder, + void *data) { char *ret; unsigned int estimated_len; @@ -485,7 +535,7 @@ cp_canonicalize_string_no_typedefs (const char *string) if (info != NULL) { /* Replace all the typedefs in the tree. */ - replace_typedefs (info, info->tree); + replace_typedefs (info, info->tree, finder, data); /* Convert the tree back into a string. */ ret = cp_comp_to_string (info->tree, estimated_len); @@ -506,6 +556,15 @@ cp_canonicalize_string_no_typedefs (const char *string) return ret; } +/* Like cp_canonicalize_string_full, but always passes NULL for + FINDER. */ + +char * +cp_canonicalize_string_no_typedefs (const char *string) +{ + return cp_canonicalize_string_full (string, NULL, NULL); +} + /* Parse STRING and convert it to canonical form. If parsing fails, or if STRING is already canonical, return NULL. Otherwise return the canonical form. The return value is allocated via xmalloc. */ @@ -528,6 +587,13 @@ cp_canonicalize_string (const char *string) ret = cp_comp_to_string (info->tree, estimated_len); cp_demangled_name_parse_free (info); + if (ret == NULL) + { + warning (_("internal error: string \"%s\" failed to be canonicalized"), + string); + return NULL; + } + if (strcmp (string, ret) == 0) { xfree (ret); @@ -1145,14 +1211,12 @@ static void make_symbol_overload_list_block (const char *name, const struct block *block) { - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym; - const struct dictionary *dict = BLOCK_DICT (block); - - for (sym = dict_iter_name_first (dict, name, &iter); + for (sym = block_iter_name_first (block, name, &iter); sym != NULL; - sym = dict_iter_name_next (name, &iter)) + sym = block_iter_name_next (name, &iter)) overload_list_add_symbol (sym, name); } @@ -1198,7 +1262,7 @@ make_symbol_overload_list_adl_namespace (struct type *type, const char *func_name) { char *namespace; - char *type_name; + const char *type_name; int i, prefix_len; while (TYPE_CODE (type) == TYPE_CODE_PTR @@ -1327,12 +1391,9 @@ make_symbol_overload_list_using (const char *func_name, static void make_symbol_overload_list_qualified (const char *func_name) { - struct symbol *sym; struct symtab *s; struct objfile *objfile; const struct block *b, *surrounding_static_block = 0; - struct dict_iterator iter; - const struct dictionary *dict; /* Look through the partial symtabs for all symbols which begin by matching FUNC_NAME. Make sure we read that symbol table in. */ @@ -1451,109 +1512,16 @@ first_component_command (char *arg, int from_tty) extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */ -#define SKIP_SPACE(P) \ - do \ - { \ - while (*(P) == ' ' || *(P) == '\t') \ - ++(P); \ - } \ - while (0) - -/* Returns the length of the operator name or 0 if INPUT does not - point to a valid C++ operator. INPUT should start with - "operator". */ -int -cp_validate_operator (const char *input) -{ - int i; - char *copy; - const char *p; - struct expression *expr; - struct value *val; - struct gdb_exception except; - - p = input; - - if (strncmp (p, "operator", 8) == 0) - { - int valid = 0; - - p += 8; - SKIP_SPACE (p); - for (i = 0; - i < sizeof (operator_tokens) / sizeof (operator_tokens[0]); - ++i) - { - int length = strlen (operator_tokens[i]); - - /* By using strncmp here, we MUST have operator_tokens - ordered! See additional notes where operator_tokens is - defined above. */ - if (strncmp (p, operator_tokens[i], length) == 0) - { - const char *op = p; - - valid = 1; - p += length; - - if (strncmp (op, "new", 3) == 0 - || strncmp (op, "delete", 6) == 0) - { - - /* Special case: new[] and delete[]. We must be - careful to swallow whitespace before/in "[]". */ - SKIP_SPACE (p); - - if (*p == '[') - { - ++p; - SKIP_SPACE (p); - if (*p == ']') - ++p; - else - valid = 0; - } - } - - if (valid) - return (p - input); - } - } - - /* Check input for a conversion operator. */ - - /* Skip past base typename. */ - while (*p != '*' && *p != '&' && *p != 0 && *p != ' ') - ++p; - SKIP_SPACE (p); - - /* Add modifiers '*' / '&'. */ - while (*p == '*' || *p == '&') - { - ++p; - SKIP_SPACE (p); - } - - /* Check for valid type. [Remember: input starts with - "operator".] */ - copy = savestring (input + 8, p - input - 8); - expr = NULL; - val = NULL; - TRY_CATCH (except, RETURN_MASK_ALL) - { - expr = parse_expression (copy); - val = evaluate_type (expr); - } - xfree (copy); - if (expr) - xfree (expr); +/* Implement "info vtbl". */ - if (val != NULL && value_type (val) != NULL) - return (p - input); - } +static void +info_vtbl_command (char *arg, int from_tty) +{ + struct value *value; - return 0; + value = parse_and_eval (arg); + cplus_print_vtable (value); } void @@ -1574,4 +1542,10 @@ _initialize_cp_support (void) first_component_command, _("Print the first class/namespace component of NAME."), &maint_cplus_cmd_list); + + add_info ("vtbl", info_vtbl_command, + _("Show the virtual function table for a C++ object.\n\ +Usage: info vtbl EXPRESSION\n\ +Evaluate EXPRESSION and display the virtual function table for the\n\ +resulting object.")); } diff --git a/contrib/gdb-7/gdb/cp-support.h b/contrib/gdb-7/gdb/cp-support.h index 8898807bfa..c7141d51cd 100644 --- a/contrib/gdb-7/gdb/cp-support.h +++ b/contrib/gdb-7/gdb/cp-support.h @@ -1,5 +1,5 @@ /* Helper routines for C++ support in GDB. - Copyright (C) 2002-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. Contributed by MontaVista Software. Namespace support contributed by David Carlton. @@ -26,6 +26,7 @@ #include "symtab.h" #include "vec.h" +#include "gdb_vecs.h" #include "gdb_obstack.h" /* Opaque declarations. */ @@ -124,11 +125,11 @@ struct demangle_parse_info struct using_direct { - char *import_src; - char *import_dest; + const char *import_src; + const char *import_dest; - char *alias; - char *declaration; + const char *alias; + const char *declaration; struct using_direct *next; @@ -148,6 +149,12 @@ extern char *cp_canonicalize_string (const char *string); extern char *cp_canonicalize_string_no_typedefs (const char *string); +typedef const char *(canonicalization_ftype) (struct type *, void *); + +extern char *cp_canonicalize_string_full (const char *string, + canonicalization_ftype *finder, + void *data); + extern char *cp_class_name_from_physname (const char *physname); extern char *method_name_from_physname (const char *physname); @@ -170,32 +177,18 @@ extern struct symbol **make_symbol_overload_list_adl (struct type **arg_types, extern struct type *cp_lookup_rtti_type (const char *name, struct block *block); -extern int cp_validate_operator (const char *input); - /* Functions/variables from cp-namespace.c. */ extern int cp_is_anonymous (const char *namespace); -DEF_VEC_P (const_char_ptr); - extern void cp_add_using_directive (const char *dest, const char *src, const char *alias, const char *declaration, VEC (const_char_ptr) *excludes, + int copy_names, struct obstack *obstack); -extern void cp_initialize_namespace (void); - -extern void cp_finalize_namespace (struct block *static_block, - struct obstack *obstack); - -extern void cp_set_block_scope (const struct symbol *symbol, - struct block *block, - struct obstack *obstack, - const char *processing_current_prefix, - int processing_has_namespace_info); - extern void cp_scan_for_anonymous_namespaces (const struct symbol *symbol, struct objfile *objfile); @@ -221,9 +214,9 @@ extern struct symbol *cp_lookup_symbol_imports_or_template const struct block *block, const domain_enum domain); -extern struct type *cp_lookup_nested_type (struct type *parent_type, - const char *nested_name, - const struct block *block); +extern struct symbol *cp_lookup_nested_symbol (struct type *parent_type, + const char *nested_name, + const struct block *block); struct type *cp_lookup_transparent_type (const char *name); diff --git a/contrib/gdb-7/gdb/cp-valprint.c b/contrib/gdb-7/gdb/cp-valprint.c index 7df9adfba4..9a8b4d3008 100644 --- a/contrib/gdb-7/gdb/cp-valprint.c +++ b/contrib/gdb-7/gdb/cp-valprint.c @@ -1,7 +1,6 @@ /* Support for printing C++ values for GDB, the GNU debugger. - Copyright (C) 1986, 1988-1989, 1991-1997, 2000-2003, 2005-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -37,6 +36,7 @@ #include "language.h" #include "python/python.h" #include "exceptions.h" +#include "typeprint.h" /* Controls printing of vtbl's. */ static void @@ -98,7 +98,7 @@ const char vtbl_ptr_name[] = "__vtbl_ptr_type"; int cp_is_vtbl_ptr_type (struct type *type) { - char *typename = type_name_no_tag (type); + const char *typename = type_name_no_tag (type); return (typename != NULL && !strcmp (typename, vtbl_ptr_name)); } @@ -210,7 +210,9 @@ cp_print_value_fields (struct type *type, struct type *real_type, { int statmem_obstack_initial_size = 0; int stat_array_obstack_initial_size = 0; - + struct type *vptr_basetype = NULL; + int vptr_fieldno; + if (dont_print_statmem == 0) { statmem_obstack_initial_size = @@ -225,6 +227,7 @@ cp_print_value_fields (struct type *type, struct type *real_type, } } + vptr_fieldno = get_vptr_fieldno (type, &vptr_basetype); for (i = n_baseclasses; i < len; i++) { /* If requested, skip printing of static fields. */ @@ -256,42 +259,21 @@ cp_print_value_fields (struct type *type, struct type *real_type, { wrap_here (n_spaces (2 + 2 * recurse)); } - if (options->inspect_it) - { - if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR) - fputs_filtered ("\"( ptr \"", stream); - else - fputs_filtered ("\"( nodef \"", stream); - if (field_is_static (&TYPE_FIELD (type, i))) - fputs_filtered ("static ", stream); - fprintf_symbol_filtered (stream, - TYPE_FIELD_NAME (type, i), - current_language->la_language, - DMGL_PARAMS | DMGL_ANSI); - fputs_filtered ("\" \"", stream); - fprintf_symbol_filtered (stream, - TYPE_FIELD_NAME (type, i), - current_language->la_language, - DMGL_PARAMS | DMGL_ANSI); - fputs_filtered ("\") \"", stream); - } - else - { - annotate_field_begin (TYPE_FIELD_TYPE (type, i)); - - if (field_is_static (&TYPE_FIELD (type, i))) - fputs_filtered ("static ", stream); - fprintf_symbol_filtered (stream, - TYPE_FIELD_NAME (type, i), - current_language->la_language, - DMGL_PARAMS | DMGL_ANSI); - annotate_field_name_end (); - /* Do not print leading '=' in case of anonymous - unions. */ - if (strcmp (TYPE_FIELD_NAME (type, i), "")) - fputs_filtered (" = ", stream); - annotate_field_value (); - } + + annotate_field_begin (TYPE_FIELD_TYPE (type, i)); + + if (field_is_static (&TYPE_FIELD (type, i))) + fputs_filtered ("static ", stream); + fprintf_symbol_filtered (stream, + TYPE_FIELD_NAME (type, i), + current_language->la_language, + DMGL_PARAMS | DMGL_ANSI); + annotate_field_name_end (); + /* Do not print leading '=' in case of anonymous + unions. */ + if (strcmp (TYPE_FIELD_NAME (type, i), "")) + fputs_filtered (" = ", stream); + annotate_field_value (); if (!field_is_static (&TYPE_FIELD (type, i)) && TYPE_FIELD_PACKED (type, i)) @@ -358,6 +340,21 @@ cp_print_value_fields (struct type *type, struct type *real_type, v, stream, recurse + 1, options); } + else if (i == vptr_fieldno && type == vptr_basetype) + { + int i_offset = offset + TYPE_FIELD_BITPOS (type, i) / 8; + struct type *i_type = TYPE_FIELD_TYPE (type, i); + + if (valprint_check_validity (stream, i_type, i_offset, val)) + { + CORE_ADDR addr; + + addr = extract_typed_address (valaddr + i_offset, i_type); + print_function_pointer_address (options, + get_type_arch (type), + addr, stream); + } + } else { struct value_print_options opts = *options; @@ -495,7 +492,7 @@ cp_print_value (struct type *type, struct type *real_type, int boffset = 0; int skip; struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); - char *basename = TYPE_NAME (baseclass); + const char *basename = TYPE_NAME (baseclass); const gdb_byte *base_valaddr = NULL; const struct value *base_val = NULL; volatile struct gdb_exception ex; @@ -539,9 +536,11 @@ cp_print_value (struct type *type, struct type *real_type, if ((boffset + offset) < 0 || (boffset + offset) >= TYPE_LENGTH (real_type)) { - /* FIXME (alloca): unsafe if baseclass is really - really large. */ - gdb_byte *buf = alloca (TYPE_LENGTH (baseclass)); + gdb_byte *buf; + struct cleanup *back_to; + + buf = xmalloc (TYPE_LENGTH (baseclass)); + back_to = make_cleanup (xfree, buf); if (target_read_memory (address + boffset, buf, TYPE_LENGTH (baseclass)) != 0) @@ -553,6 +552,7 @@ cp_print_value (struct type *type, struct type *real_type, boffset = 0; thistype = baseclass; base_valaddr = value_contents_for_printing_const (base_val); + do_cleanups (back_to); } else { @@ -794,14 +794,14 @@ cp_print_class_member (const gdb_byte *valaddr, struct type *type, if (domain != NULL) { - char *name; + const char *name; fputs_filtered (prefix, stream); name = type_name_no_tag (domain); if (name) fputs_filtered (name, stream); else - c_type_print_base (domain, stream, 0, 0); + c_type_print_base (domain, stream, 0, 0, &type_print_raw_options); fprintf_filtered (stream, "::"); fputs_filtered (TYPE_FIELD_NAME (domain, fieldno), stream); } diff --git a/contrib/gdb-7/gdb/d-lang.c b/contrib/gdb-7/gdb/d-lang.c index da2785c90c..15f56dfaf0 100644 --- a/contrib/gdb-7/gdb/d-lang.c +++ b/contrib/gdb-7/gdb/d-lang.c @@ -1,6 +1,6 @@ /* D language support routines for GDB, the GNU debugger. - Copyright (C) 2005-2006, 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -240,7 +240,6 @@ static const struct language_defn d_language_defn = "d", language_d, range_check_off, - type_check_off, case_sensitive_on, array_row_major, macro_expansion_c, @@ -256,6 +255,7 @@ static const struct language_defn d_language_defn = syntax. */ d_val_print, /* Print a value using appropriate syntax. */ c_value_print, /* Print a top-level value. */ + default_read_var_value, /* la_read_var_value */ NULL, /* Language specific skip_trampoline. */ "this", basic_lookup_symbol_nonlocal, @@ -272,11 +272,14 @@ static const struct language_defn d_language_defn = default_print_array_index, default_pass_by_reference, c_get_string, - strcmp_iw_ordered, - NULL, + NULL, /* la_get_symbol_name_cmp */ + iterate_over_symbols, LANG_MAGIC }; +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_d_language; + void _initialize_d_language (void) { diff --git a/contrib/gdb-7/gdb/d-lang.h b/contrib/gdb-7/gdb/d-lang.h index 67ca14cb47..fb6678a16d 100644 --- a/contrib/gdb-7/gdb/d-lang.h +++ b/contrib/gdb-7/gdb/d-lang.h @@ -1,6 +1,6 @@ /* D language support definitions for GDB, the GNU debugger. - Copyright (C) 2005-2006, 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -24,10 +24,10 @@ extern char *d_demangle (const char *mangled, int options); -extern int d_val_print (struct type *type, const gdb_byte *valaddr, - int embedded_offset, CORE_ADDR address, - struct ui_file *stream, int recurse, - const struct value *val, - const struct value_print_options *options); +extern void d_val_print (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int recurse, + const struct value *val, + const struct value_print_options *options); #endif /* !defined (D_LANG_H) */ diff --git a/contrib/gdb-7/gdb/d-valprint.c b/contrib/gdb-7/gdb/d-valprint.c index 527c08784e..6e9c28d08d 100644 --- a/contrib/gdb-7/gdb/d-valprint.c +++ b/contrib/gdb-7/gdb/d-valprint.c @@ -1,6 +1,6 @@ /* Support for printing D values for GDB, the GNU debugger. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -23,10 +23,10 @@ #include "d-lang.h" #include "c-lang.h" -/* Assuming that TYPE is a TYPE_CODE_STRUCT, verify that TYPE is - a dynamic array, and then print its value to STREAM. Return - the number of string characters printed, or -1 if TYPE is not - a dynamic array. */ +/* Assuming that TYPE is a TYPE_CODE_STRUCT, verify that TYPE is a + dynamic array, and then print its value to STREAM. Return zero if + TYPE is a dynamic array, non-zero otherwise. */ + static int dynamic_array_type (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR address, @@ -60,16 +60,17 @@ dynamic_array_type (struct type *type, const gdb_byte *valaddr, true_type = lookup_array_range_type (true_type, 0, length - 1); ival = value_at (true_type, addr); - return d_val_print (true_type, - value_contents_for_printing (ival), - value_embedded_offset (ival), addr, - stream, recurse + 1, ival, options); + d_val_print (true_type, + value_contents_for_printing (ival), + value_embedded_offset (ival), addr, + stream, recurse + 1, ival, options); + return 0; } - return -1; + return 1; } /* Implements the la_val_print routine for language D. */ -int +void d_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR address, struct ui_file *stream, int recurse, const struct value *val, @@ -83,12 +84,10 @@ d_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, case TYPE_CODE_STRUCT: ret = dynamic_array_type (type, valaddr, embedded_offset, address, stream, recurse, val, options); - if (ret != -1) - break; + if (ret == 0) + break; default: - ret = c_val_print (type, valaddr, embedded_offset, address, stream, - recurse, val, options); + c_val_print (type, valaddr, embedded_offset, address, stream, + recurse, val, options); } - - return ret; } diff --git a/contrib/gdb-7/gdb/data-directory/Makefile.in b/contrib/gdb-7/gdb/data-directory/Makefile.in index 4296e5ada7..d98ac77145 100644 --- a/contrib/gdb-7/gdb/data-directory/Makefile.in +++ b/contrib/gdb-7/gdb/data-directory/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2012 Free Software Foundation, Inc. +# Copyright (C) 2010-2013 Free Software Foundation, Inc. # Makefile for building a staged copy of the data-directory. # This file is part of GDB. @@ -57,8 +57,12 @@ PYTHON_FILES = \ gdb/printing.py \ gdb/prompt.py \ gdb/command/__init__.py \ + gdb/command/type_printers.py \ gdb/command/pretty_printers.py \ - gdb/command/prompt.py + gdb/command/prompt.py \ + gdb/command/explore.py \ + gdb/function/__init__.py \ + gdb/function/strfns.py FLAGS_TO_PASS = \ "prefix=$(prefix)" \ diff --git a/contrib/gdb-7/gdb/dbxread.c b/contrib/gdb-7/gdb/dbxread.c index adf8315759..09b46a024a 100644 --- a/contrib/gdb-7/gdb/dbxread.c +++ b/contrib/gdb-7/gdb/dbxread.c @@ -1,5 +1,5 @@ /* Read dbx symbol tables and convert to internal format, for GDB. - Copyright (C) 1986-2004, 2008-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -55,6 +55,7 @@ #include "cp-abi.h" #include "cp-support.h" #include "psympriv.h" +#include "block.h" #include "gdb_assert.h" #include "gdb_string.h" @@ -64,6 +65,10 @@ native, now. */ +/* Key for dbx-associated data. */ + +const struct objfile_data *dbx_objfile_data_key; + /* We put a pointer to this structure in the read_symtab_private field of the psymtab. */ @@ -255,11 +260,12 @@ static int bincls_allocated; extern void _initialize_dbxread (void); -static void read_ofile_symtab (struct partial_symtab *); +static void read_ofile_symtab (struct objfile *, struct partial_symtab *); -static void dbx_psymtab_to_symtab (struct partial_symtab *); +static void dbx_read_symtab (struct partial_symtab *self, + struct objfile *objfile); -static void dbx_psymtab_to_symtab_1 (struct partial_symtab *); +static void dbx_psymtab_to_symtab_1 (struct objfile *, struct partial_symtab *); static void read_dbx_dynamic_symtab (struct objfile *objfile); @@ -624,12 +630,11 @@ dbx_symfile_init (struct objfile *objfile) char *name = bfd_get_filename (sym_bfd); asection *text_sect; unsigned char size_temp[DBX_STRINGTAB_SIZE_SIZE]; + struct dbx_symfile_info *dbx; /* Allocate struct to keep track of the symfile. */ - objfile->deprecated_sym_stab_info = (struct dbx_symfile_info *) - xmalloc (sizeof (struct dbx_symfile_info)); - memset (objfile->deprecated_sym_stab_info, 0, - sizeof (struct dbx_symfile_info)); + dbx = XCNEW (struct dbx_symfile_info); + set_objfile_data (objfile, dbx_objfile_data_key, dbx); DBX_TEXT_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".text"); DBX_DATA_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".data"); @@ -737,24 +742,30 @@ dbx_symfile_init (struct objfile *objfile) static void dbx_symfile_finish (struct objfile *objfile) { - if (objfile->deprecated_sym_stab_info != NULL) + free_header_files (); +} + +static void +dbx_free_symfile_info (struct objfile *objfile, void *arg) +{ + struct dbx_symfile_info *dbx = arg; + + if (dbx->header_files != NULL) { - if (HEADER_FILES (objfile) != NULL) - { - int i = N_HEADER_FILES (objfile); - struct header_file *hfiles = HEADER_FILES (objfile); + int i = dbx->n_header_files; + struct header_file *hfiles = dbx->header_files; - while (--i >= 0) - { - xfree (hfiles[i].name); - xfree (hfiles[i].vector); - } - xfree (hfiles); + while (--i >= 0) + { + xfree (hfiles[i].name); + xfree (hfiles[i].vector); } - xfree (objfile->deprecated_sym_stab_info); + xfree (hfiles); } - free_header_files (); + + xfree (dbx); } + /* Buffer for reading the symbol table entries. */ @@ -1210,7 +1221,7 @@ read_dbx_symtab (struct objfile *objfile) struct partial_symtab *pst; /* List of current psymtab's include files. */ - char **psymtab_include_list; + const char **psymtab_include_list; int includes_allocated; int includes_used; @@ -1232,8 +1243,8 @@ read_dbx_symtab (struct objfile *objfile) includes_allocated = 30; includes_used = 0; - psymtab_include_list = (char **) alloca (includes_allocated * - sizeof (char *)); + psymtab_include_list = (const char **) alloca (includes_allocated * + sizeof (const char *)); dependencies_allocated = 30; dependencies_used = 0; @@ -1245,7 +1256,7 @@ read_dbx_symtab (struct objfile *objfile) init_bincl_list (20, objfile); back_to = make_cleanup_free_bincl_list (objfile); - last_source_file = NULL; + set_last_source_file (NULL); lowest_text_address = (CORE_ADDR) -1; @@ -1379,8 +1390,8 @@ read_dbx_symtab (struct objfile *objfile) which are not the address. */ && nlist.n_value >= pst->textlow) { - end_psymtab (pst, psymtab_include_list, includes_used, - symnum * symbol_size, + end_psymtab (objfile, pst, psymtab_include_list, + includes_used, symnum * symbol_size, nlist.n_value > pst->texthigh ? nlist.n_value : pst->texthigh, dependency_list, dependencies_used, @@ -1498,8 +1509,8 @@ read_dbx_symtab (struct objfile *objfile) if (pst) { - end_psymtab (pst, psymtab_include_list, includes_used, - symnum * symbol_size, + end_psymtab (objfile, pst, psymtab_include_list, + includes_used, symnum * symbol_size, valu > pst->texthigh ? valu : pst->texthigh, dependency_list, dependencies_used, prev_textlow_not_set); @@ -1635,12 +1646,12 @@ read_dbx_symtab (struct objfile *objfile) psymtab_include_list[includes_used++] = namestring; if (includes_used >= includes_allocated) { - char **orig = psymtab_include_list; + const char **orig = psymtab_include_list; - psymtab_include_list = (char **) - alloca ((includes_allocated *= 2) * sizeof (char *)); + psymtab_include_list = (const char **) + alloca ((includes_allocated *= 2) * sizeof (const char *)); memcpy (psymtab_include_list, orig, - includes_used * sizeof (char *)); + includes_used * sizeof (const char *)); } continue; } @@ -1696,8 +1707,8 @@ read_dbx_symtab (struct objfile *objfile) if (new_name != NULL) { sym_len = strlen (new_name); - sym_name = obsavestring (new_name, sym_len, - &objfile->objfile_obstack); + sym_name = obstack_copy0 (&objfile->objfile_obstack, + new_name, sym_len); xfree (new_name); } xfree (name); @@ -2109,7 +2120,7 @@ read_dbx_symtab (struct objfile *objfile) follows this module. */ if (pst && gdbarch_sofun_address_maybe_missing (gdbarch)) { - end_psymtab (pst, psymtab_include_list, includes_used, + end_psymtab (objfile, pst, psymtab_include_list, includes_used, symnum * symbol_size, (CORE_ADDR) 0, dependency_list, dependencies_used, textlow_not_set); @@ -2172,7 +2183,7 @@ read_dbx_symtab (struct objfile *objfile) : lowest_text_address) + text_size; - end_psymtab (pst, psymtab_include_list, includes_used, + end_psymtab (objfile, pst, psymtab_include_list, includes_used, symnum * symbol_size, text_end > pst->texthigh ? text_end : pst->texthigh, dependency_list, dependencies_used, textlow_not_set); @@ -2200,7 +2211,7 @@ start_psymtab (struct objfile *objfile, char *filename, CORE_ADDR textlow, result->read_symtab_private = obstack_alloc (&objfile->objfile_obstack, sizeof (struct symloc)); LDSYMOFF (result) = ldsymoff; - result->read_symtab = dbx_psymtab_to_symtab; + result->read_symtab = dbx_read_symtab; SYMBOL_SIZE (result) = symbol_size; SYMBOL_OFFSET (result) = symbol_table_offset; STRING_OFFSET (result) = string_table_offset; @@ -2226,13 +2237,13 @@ start_psymtab (struct objfile *objfile, char *filename, CORE_ADDR textlow, FIXME: List variables and peculiarities of same. */ struct partial_symtab * -end_psymtab (struct partial_symtab *pst, char **include_list, int num_includes, +end_psymtab (struct objfile *objfile, struct partial_symtab *pst, + const char **include_list, int num_includes, int capping_symbol_offset, CORE_ADDR capping_text, struct partial_symtab **dependency_list, int number_dependencies, int textlow_not_set) { int i; - struct objfile *objfile = pst->objfile; struct gdbarch *gdbarch = get_objfile_arch (objfile); if (capping_symbol_offset != -1) @@ -2367,7 +2378,7 @@ end_psymtab (struct partial_symtab *pst, char **include_list, int num_includes, subpst->read_symtab = pst->read_symtab; } - sort_pst_symbols (pst); + sort_pst_symbols (objfile, pst); if (num_includes == 0 && number_dependencies == 0 @@ -2383,7 +2394,7 @@ end_psymtab (struct partial_symtab *pst, char **include_list, int num_includes, is not empty, but we don't realize that. Fixing that without slowing things down might be tricky. */ - discard_psymtab (pst); + discard_psymtab (objfile, pst); /* Indicate that psymtab was thrown away. */ pst = (struct partial_symtab *) NULL; @@ -2392,14 +2403,11 @@ end_psymtab (struct partial_symtab *pst, char **include_list, int num_includes, } static void -dbx_psymtab_to_symtab_1 (struct partial_symtab *pst) +dbx_psymtab_to_symtab_1 (struct objfile *objfile, struct partial_symtab *pst) { struct cleanup *old_chain; int i; - if (!pst) - return; - if (pst->readin) { fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. " @@ -2423,7 +2431,7 @@ dbx_psymtab_to_symtab_1 (struct partial_symtab *pst) wrap_here (""); /* Flush output. */ gdb_flush (gdb_stdout); } - dbx_psymtab_to_symtab_1 (pst->dependencies[i]); + dbx_psymtab_to_symtab_1 (objfile, pst->dependencies[i]); } if (LDSYMLEN (pst)) /* Otherwise it's a dummy. */ @@ -2436,8 +2444,8 @@ dbx_psymtab_to_symtab_1 (struct partial_symtab *pst) symbol_size = SYMBOL_SIZE (pst); /* Read in this file's symbols. */ - bfd_seek (pst->objfile->obfd, SYMBOL_OFFSET (pst), SEEK_SET); - read_ofile_symtab (pst); + bfd_seek (objfile->obfd, SYMBOL_OFFSET (pst), SEEK_SET); + read_ofile_symtab (objfile, pst); do_cleanups (old_chain); } @@ -2446,44 +2454,41 @@ dbx_psymtab_to_symtab_1 (struct partial_symtab *pst) } /* Read in all of the symbols for a given psymtab for real. - Be verbose about it if the user wants that. */ + Be verbose about it if the user wants that. SELF is not NULL. */ static void -dbx_psymtab_to_symtab (struct partial_symtab *pst) +dbx_read_symtab (struct partial_symtab *self, struct objfile *objfile) { bfd *sym_bfd; struct cleanup *back_to = NULL; - if (!pst) - return; - - if (pst->readin) + if (self->readin) { fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. " "Shouldn't happen.\n", - pst->filename); + self->filename); return; } - if (LDSYMLEN (pst) || pst->number_of_dependencies) + if (LDSYMLEN (self) || self->number_of_dependencies) { /* Print the message now, before reading the string table, to avoid disconcerting pauses. */ if (info_verbose) { - printf_filtered ("Reading in symbols for %s...", pst->filename); + printf_filtered ("Reading in symbols for %s...", self->filename); gdb_flush (gdb_stdout); } - sym_bfd = pst->objfile->obfd; + sym_bfd = objfile->obfd; next_symbol_text_func = dbx_next_symbol_text; - if (DBX_STAB_SECTION (pst->objfile)) + if (DBX_STAB_SECTION (objfile)) { stabs_data - = symfile_relocate_debug_section (pst->objfile, - DBX_STAB_SECTION (pst->objfile), + = symfile_relocate_debug_section (objfile, + DBX_STAB_SECTION (objfile), NULL); if (stabs_data) @@ -2491,14 +2496,14 @@ dbx_psymtab_to_symtab (struct partial_symtab *pst) (void *) &stabs_data); } - dbx_psymtab_to_symtab_1 (pst); + dbx_psymtab_to_symtab_1 (objfile, self); if (back_to) do_cleanups (back_to); /* Match with global symbols. This only needs to be done once, after all of the symtabs and dependencies have been read in. */ - scan_file_globals (pst->objfile); + scan_file_globals (objfile); /* Finish up the debug error message. */ if (info_verbose) @@ -2509,7 +2514,7 @@ dbx_psymtab_to_symtab (struct partial_symtab *pst) /* Read in a defined section of a specific object file's symbols. */ static void -read_ofile_symtab (struct partial_symtab *pst) +read_ofile_symtab (struct objfile *objfile, struct partial_symtab *pst) { char *namestring; struct external_nlist *bufp; @@ -2517,14 +2522,12 @@ read_ofile_symtab (struct partial_symtab *pst) unsigned char type; unsigned max_symnum; bfd *abfd; - struct objfile *objfile; int sym_offset; /* Offset to start of symbols to read */ int sym_size; /* Size of symbols to read */ CORE_ADDR text_offset; /* Start of text segment for symbols */ int text_size; /* Size of text segment for symbols */ struct section_offsets *section_offsets; - objfile = pst->objfile; sym_offset = LDSYMOFF (pst); sym_size = LDSYMLEN (pst); text_offset = pst->textlow; @@ -2539,7 +2542,7 @@ read_ofile_symtab (struct partial_symtab *pst) subfile_stack = NULL; stringtab_global = DBX_STRINGTAB (objfile); - last_source_file = NULL; + set_last_source_file (NULL); abfd = objfile->obfd; symfile_bfd = objfile->obfd; /* Implicit param to next_text_symbol. */ @@ -2704,6 +2707,34 @@ read_ofile_symtab (struct partial_symtab *pst) } +/* Record the namespace that the function defined by SYMBOL was + defined in, if necessary. BLOCK is the associated block; use + OBSTACK for allocation. */ + +static void +cp_set_block_scope (const struct symbol *symbol, + struct block *block, + struct obstack *obstack) +{ + if (SYMBOL_DEMANGLED_NAME (symbol) != NULL) + { + /* Try to figure out the appropriate namespace from the + demangled name. */ + + /* FIXME: carlton/2003-04-15: If the function in question is + a method of a class, the name will actually include the + name of the class as well. This should be harmless, but + is a little unfortunate. */ + + const char *name = SYMBOL_DEMANGLED_NAME (symbol); + unsigned int prefix_len = cp_entire_prefix_len (name); + + block_set_scope (block, + obstack_copy0 (obstack, name, prefix_len), + obstack); + } +} + /* This handles a single symbol from the symbol-file, building symbols into a GDB symtab. It takes these arguments and an implicit argument. @@ -2763,7 +2794,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, /* Something is wrong if we see real data before seeing a source file name. */ - if (last_source_file == NULL && type != (unsigned char) N_SO) + if (get_last_source_file () == NULL && type != (unsigned char) N_SO) { /* Ignore any symbols which appear before an N_SO symbol. Currently no one puts symbols there, but we should deal @@ -2811,8 +2842,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, /* For C++, set the block's scope. */ if (SYMBOL_LANGUAGE (new->name) == language_cplus) - cp_set_block_scope (new->name, block, &objfile->objfile_obstack, - "", 0); + cp_set_block_scope (new->name, block, &objfile->objfile_obstack); /* May be switching to an assembler file which may not be using block relative stabs, so reset the offset. */ @@ -2826,7 +2856,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, /* Relocate for dynamic loading. */ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); - valu = gdbarch_smash_text_address (gdbarch, valu); + valu = gdbarch_addr_bits_remove (gdbarch, valu); last_function_start = valu; goto define_a_symbol; @@ -2939,7 +2969,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, n_opt_found = 0; - if (last_source_file) + if (get_last_source_file ()) { /* Check if previous symbol was also an N_SO (with some sanity checks). If so, that one was actually the @@ -3172,7 +3202,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, && gdbarch_sofun_address_maybe_missing (gdbarch)) { CORE_ADDR minsym_valu = - find_stab_function_addr (name, last_source_file, objfile); + find_stab_function_addr (name, get_last_source_file (), + objfile); /* The function find_stab_function_addr will return 0 if the minimal symbol wasn't found. @@ -3216,8 +3247,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, /* For C++, set the block's scope. */ if (SYMBOL_LANGUAGE (new->name) == language_cplus) cp_set_block_scope (new->name, block, - &objfile->objfile_obstack, - "", 0); + &objfile->objfile_obstack); } new = push_context (0, valu); @@ -3346,7 +3376,7 @@ coffstab_build_psymtabs (struct objfile *objfile, /* There is already a dbx_symfile_info allocated by our caller. It might even contain some info from the coff symtab to help us. */ - info = objfile->deprecated_sym_stab_info; + info = DBX_SYMFILE_INFO (objfile); DBX_TEXT_ADDR (objfile) = textaddr; DBX_TEXT_SIZE (objfile) = textsize; @@ -3435,7 +3465,7 @@ elfstab_build_psymtabs (struct objfile *objfile, asection *stabsect, /* There is already a dbx_symfile_info allocated by our caller. It might even contain some info from the ELF symtab to help us. */ - info = objfile->deprecated_sym_stab_info; + info = DBX_SYMFILE_INFO (objfile); /* Find the first and last text address. dbx_symfile_read seems to want this. */ @@ -3514,6 +3544,7 @@ stabsect_build_psymtabs (struct objfile *objfile, char *stab_name, asection *stabsect; asection *stabstrsect; asection *text_sect; + struct dbx_symfile_info *dbx; stabsect = bfd_get_section_by_name (sym_bfd, stab_name); stabstrsect = bfd_get_section_by_name (sym_bfd, stabstr_name); @@ -3526,10 +3557,8 @@ stabsect_build_psymtabs (struct objfile *objfile, char *stab_name, "but not string section (%s)"), stab_name, stabstr_name); - objfile->deprecated_sym_stab_info = (struct dbx_symfile_info *) - xmalloc (sizeof (struct dbx_symfile_info)); - memset (objfile->deprecated_sym_stab_info, 0, - sizeof (struct dbx_symfile_info)); + dbx = XCNEW (struct dbx_symfile_info); + set_objfile_data (objfile, dbx_objfile_data_key, dbx); text_sect = bfd_get_section_by_name (sym_bfd, text_name); if (!text_sect) @@ -3588,6 +3617,7 @@ static const struct sym_fns aout_sym_fns = default_symfile_segments, /* Get segment information from a file. */ NULL, default_symfile_relocate, /* Relocate a debug section. */ + NULL, /* sym_probe_fns */ &psym_functions }; @@ -3595,4 +3625,7 @@ void _initialize_dbxread (void) { add_symtab_fns (&aout_sym_fns); + + dbx_objfile_data_key + = register_objfile_data_with_cleanup (NULL, dbx_free_symfile_info); } diff --git a/contrib/gdb-7/gdb/dcache.c b/contrib/gdb-7/gdb/dcache.c index 652cfab9e0..6e2c7a2905 100644 --- a/contrib/gdb-7/gdb/dcache.c +++ b/contrib/gdb-7/gdb/dcache.c @@ -1,7 +1,6 @@ /* Caching code for GDB, the GNU debugger. - Copyright (C) 1992-1993, 1995-1996, 1998-2001, 2003, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -589,7 +588,7 @@ dcache_print_line (int index) db = (struct dcache_block *) n->value; printf_filtered (_("Line %d: address %s [%d hits]\n"), - index, paddress (target_gdbarch, db->addr), db->refs); + index, paddress (target_gdbarch (), db->addr), db->refs); for (j = 0; j < last_cache->line_size; j++) { @@ -647,7 +646,7 @@ dcache_info (char *exp, int tty) struct dcache_block *db = (struct dcache_block *) n->value; printf_filtered (_("Line %d: address %s [%d hits]\n"), - i, paddress (target_gdbarch, db->addr), db->refs); + i, paddress (target_gdbarch (), db->addr), db->refs); i++; refcount += db->refs; diff --git a/contrib/gdb-7/gdb/dcache.h b/contrib/gdb-7/gdb/dcache.h index 7e07e20986..720a887a81 100644 --- a/contrib/gdb-7/gdb/dcache.h +++ b/contrib/gdb-7/gdb/dcache.h @@ -1,8 +1,7 @@ /* Declarations for caching. Typically used by remote back ends for caching remote memory. - Copyright (C) 1992-1993, 1995, 1999-2001, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/defs.h b/contrib/gdb-7/gdb/defs.h index e4c24830db..e157d6b973 100644 --- a/contrib/gdb-7/gdb/defs.h +++ b/contrib/gdb-7/gdb/defs.h @@ -1,8 +1,7 @@ /* *INDENT-OFF* */ /* ATTRIBUTE_PRINTF confuses indent, avoid running it for now. */ /* Basic, host-specific, and target-specific definitions for GDB. - Copyright (C) 1986, 1988-2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -27,6 +26,7 @@ #endif #include "config.h" /* Generated by configure. */ +#include "build-gnulib/config.h" #include #include @@ -67,9 +67,13 @@ #include "gdb_wchar.h" -/* For ``enum target_signal''. */ +/* For ``enum gdb_signal''. */ #include "gdb/signals.h" +#include "ui-file.h" + +#include "host-defs.h" + /* Just in case they're not defined in stdio.h. */ #ifndef SEEK_SET @@ -111,8 +115,6 @@ typedef bfd_vma CORE_ADDR; /* This is to make sure that LONGEST is at least as big as CORE_ADDR. */ -#ifndef LONGEST - #ifdef BFD64 #define LONGEST BFD_HOST_64_BIT @@ -120,25 +122,11 @@ typedef bfd_vma CORE_ADDR; #else /* No BFD64 */ -#ifdef CC_HAS_LONG_LONG #define LONGEST long long #define ULONGEST unsigned long long -#else -#ifdef BFD_HOST_64_BIT -/* BFD_HOST_64_BIT is defined for some hosts that don't have long long - (e.g. i386-windows) so try it. */ -#define LONGEST BFD_HOST_64_BIT -#define ULONGEST BFD_HOST_U_64_BIT -#else -#define LONGEST long -#define ULONGEST unsigned long -#endif -#endif #endif /* No BFD64 */ -#endif /* ! LONGEST */ - #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif @@ -167,9 +155,28 @@ extern char *python_libdir; /* Search path for separate debug files. */ extern char *debug_file_directory; -extern int quit_flag; +/* GDB has two methods for handling SIGINT. When immediate_quit is + nonzero, a SIGINT results in an immediate longjmp out of the signal + handler. Otherwise, SIGINT simply sets a flag; code that might + take a long time, and which ought to be interruptible, checks this + flag using the QUIT macro. + + If GDB is built with Python support, it uses Python's low-level + interface to implement the flag. This approach makes it possible + for Python and GDB SIGINT handling to coexist seamlessly. + + If GDB is built without Python, it instead uses its traditional + variables. */ + +/* Clear the quit flag. */ +extern void clear_quit_flag (void); +/* Evaluate to non-zero if the quit flag is set, zero otherwise. This + will clear the quit flag as a side effect. */ +extern int check_quit_flag (void); +/* Set the quit flag. */ +extern void set_quit_flag (void); + extern int immediate_quit; -extern int sevenbit_strings; extern void quit (void); @@ -181,7 +188,7 @@ extern void quit (void); needed. */ #define QUIT { \ - if (quit_flag) quit (); \ + if (check_quit_flag ()) quit (); \ if (deprecated_interactive_hook) deprecated_interactive_hook (); \ } @@ -197,6 +204,7 @@ enum language language_c, /* C */ language_cplus, /* C++ */ language_d, /* D */ + language_go, /* Go */ language_objc, /* Objective-C */ language_java, /* Java */ language_fortran, /* Fortran */ @@ -251,34 +259,6 @@ enum return_value_convention RETURN_VALUE_ABI_PRESERVES_ADDRESS, }; -/* the cleanup list records things that have to be undone - if an error happens (descriptors to be closed, memory to be freed, etc.) - Each link in the chain records a function to call and an - argument to give it. - - Use make_cleanup to add an element to the cleanup chain. - Use do_cleanups to do all cleanup actions back to a given - point in the chain. Use discard_cleanups to remove cleanups - from the chain back to a given point, not doing them. - - If the argument is pointer to allocated memory, then you need - to additionally set the 'free_arg' member to a function that will - free that memory. This function will be called both when the cleanup - is executed and when it's discarded. */ - -struct cleanup - { - struct cleanup *next; - void (*function) (void *); - void (*free_arg) (void *); - void *arg; - }; - -/* vec.h-style vectors of strings want a typedef for char * or const char *. */ - -typedef char * char_ptr; -typedef const char * const_char_ptr; - /* Needed for various prototypes */ struct symtab; @@ -293,297 +273,11 @@ struct value; globals that are currently only available to main.c. */ extern char *relocate_gdb_directory (const char *initial, int flag); -/* From utils.c */ - -extern void initialize_utils (void); - -extern void notice_quit (void); - -extern int strcmp_iw (const char *, const char *); - -extern int strcmp_iw_ordered (const char *, const char *); - -extern int streq (const char *, const char *); - -extern int subset_compare (char *, char *); - -extern char *safe_strerror (int); - -extern void set_display_time (int); - -extern void set_display_space (int); - -#define ALL_CLEANUPS ((struct cleanup *)0) - -extern void do_cleanups (struct cleanup *); -extern void do_final_cleanups (struct cleanup *); - -extern void discard_cleanups (struct cleanup *); -extern void discard_final_cleanups (struct cleanup *); -extern void discard_my_cleanups (struct cleanup **, struct cleanup *); - -/* NOTE: cagney/2000-03-04: This typedef is strictly for the - make_cleanup function declarations below. Do not use this typedef - as a cast when passing functions into the make_cleanup() code. - Instead either use a bounce function or add a wrapper function. - Calling a f(char*) function with f(void*) is non-portable. */ -typedef void (make_cleanup_ftype) (void *); - -extern struct cleanup *make_cleanup (make_cleanup_ftype *, void *); - -extern struct cleanup *make_cleanup_dtor (make_cleanup_ftype *, void *, - void (*dtor) (void *)); - -extern struct cleanup *make_cleanup_freeargv (char **); - -struct dyn_string; -extern struct cleanup *make_cleanup_dyn_string_delete (struct dyn_string *); - -struct ui_file; -extern struct cleanup *make_cleanup_ui_file_delete (struct ui_file *); - -struct ui_out; -extern struct cleanup * - make_cleanup_ui_out_redirect_pop (struct ui_out *uiout); - -struct section_addr_info; -extern struct cleanup *(make_cleanup_free_section_addr_info - (struct section_addr_info *)); - -extern struct cleanup *make_cleanup_close (int fd); - -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_cleanup_restore_uinteger (unsigned int *variable); - -struct target_ops; -extern struct cleanup *make_cleanup_unpush_target (struct target_ops *ops); - -extern struct cleanup * - make_cleanup_restore_ui_file (struct ui_file **variable); - -extern struct cleanup *make_cleanup_value_free_to_mark (struct value *); -extern struct cleanup *make_cleanup_value_free (struct value *); - -struct so_list; -extern struct cleanup *make_cleanup_free_so (struct so_list *so); - -extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *); - -extern struct cleanup *make_my_cleanup (struct cleanup **, - make_cleanup_ftype *, void *); - -extern struct cleanup *make_cleanup_htab_delete (htab_t htab); - -extern struct cleanup *make_my_cleanup2 (struct cleanup **, - make_cleanup_ftype *, void *, - void (*free_arg) (void *)); - -extern struct cleanup *save_cleanups (void); -extern struct cleanup *save_final_cleanups (void); -extern struct cleanup *save_my_cleanups (struct cleanup **); - -extern void restore_cleanups (struct cleanup *); -extern void restore_final_cleanups (struct cleanup *); -extern void restore_my_cleanups (struct cleanup **, struct cleanup *); - -extern void free_current_contents (void *); - -extern void null_cleanup (void *); - -extern struct cleanup *make_command_stats_cleanup (int); - -extern int myread (int, char *, int); - -extern int query (const char *, ...) ATTRIBUTE_PRINTF (1, 2); -extern int nquery (const char *, ...) ATTRIBUTE_PRINTF (1, 2); -extern int yquery (const char *, ...) ATTRIBUTE_PRINTF (1, 2); - -extern void init_page_info (void); - -extern struct cleanup *make_cleanup_restore_page_info (void); -extern struct cleanup * - set_batch_flag_and_make_cleanup_restore_page_info (void); - -extern char *gdb_realpath (const char *); -extern char *xfullpath (const char *); - -extern unsigned long gnu_debuglink_crc32 (unsigned long crc, - unsigned char *buf, size_t len); - -ULONGEST strtoulst (const char *num, const char **trailer, int base); - -char *ldirname (const char *filename); - -char **gdb_buildargv (const char *); - -int compare_positive_ints (const void *ap, const void *bp); -int compare_strings (const void *ap, const void *bp); - -/* A wrapper for bfd_errmsg to produce a more helpful error message - in the case of bfd_error_file_ambiguously recognized. - MATCHING, if non-NULL, is the corresponding argument to - bfd_check_format_matches, and will be freed. */ - -extern const char *gdb_bfd_errmsg (bfd_error_type error_tag, char **matching); - -extern int parse_pid_to_attach (char *args); - -extern struct cleanup *make_bpstat_clear_actions_cleanup (void); - -extern int producer_is_gcc_ge_4 (const char *producer); - /* Annotation stuff. */ extern int annotation_level; /* in stack.c */ -extern void begin_line (void); - -extern void wrap_here (char *); - -extern void reinitialize_more_filter (void); - -/* Normal results */ -extern struct ui_file *gdb_stdout; -/* Input stream */ -extern struct ui_file *gdb_stdin; -/* Serious error notifications */ -extern struct ui_file *gdb_stderr; -/* Log/debug/trace messages that should bypass normal stdout/stderr - filtering. For moment, always call this stream using - *_unfiltered. In the very near future that restriction shall be - removed - either call shall be unfiltered. (cagney 1999-06-13). */ -extern struct ui_file *gdb_stdlog; -/* Target output that should bypass normal stdout/stderr filtering. - For moment, always call this stream using *_unfiltered. In the - very near future that restriction shall be removed - either call - shall be unfiltered. (cagney 1999-07-02). */ -extern struct ui_file *gdb_stdtarg; -extern struct ui_file *gdb_stdtargerr; -extern struct ui_file *gdb_stdtargin; - -#include "ui-file.h" - -/* More generic printf like operations. Filtered versions may return - non-locally on error. */ - -extern void fputs_filtered (const char *, struct ui_file *); - -extern void fputs_unfiltered (const char *, struct ui_file *); - -extern int fputc_filtered (int c, struct ui_file *); - -extern int fputc_unfiltered (int c, struct ui_file *); - -extern int putchar_filtered (int c); - -extern int putchar_unfiltered (int c); - -extern void puts_filtered (const char *); - -extern void puts_unfiltered (const char *); - -extern void puts_filtered_tabular (char *string, int width, int right); - -extern void puts_debug (char *prefix, char *string, char *suffix); - -extern void vprintf_filtered (const char *, va_list) ATTRIBUTE_PRINTF (1, 0); - -extern void vfprintf_filtered (struct ui_file *, const char *, va_list) - ATTRIBUTE_PRINTF (2, 0); - -extern void fprintf_filtered (struct ui_file *, const char *, ...) - ATTRIBUTE_PRINTF (2, 3); - -extern void fprintfi_filtered (int, struct ui_file *, const char *, ...) - ATTRIBUTE_PRINTF (3, 4); - -extern void printf_filtered (const char *, ...) ATTRIBUTE_PRINTF (1, 2); - -extern void printfi_filtered (int, const char *, ...) ATTRIBUTE_PRINTF (2, 3); - -extern void vprintf_unfiltered (const char *, va_list) ATTRIBUTE_PRINTF (1, 0); - -extern void vfprintf_unfiltered (struct ui_file *, const char *, va_list) - ATTRIBUTE_PRINTF (2, 0); - -extern void fprintf_unfiltered (struct ui_file *, const char *, ...) - ATTRIBUTE_PRINTF (2, 3); - -extern void printf_unfiltered (const char *, ...) ATTRIBUTE_PRINTF (1, 2); - -extern void print_spaces (int, struct ui_file *); - -extern void print_spaces_filtered (int, struct ui_file *); - -extern char *n_spaces (int); - -extern void fputstr_filtered (const char *str, int quotr, - struct ui_file * stream); - -extern void fputstr_unfiltered (const char *str, int quotr, - struct ui_file * stream); - -extern void fputstrn_filtered (const char *str, int n, int quotr, - struct ui_file * stream); - -extern void fputstrn_unfiltered (const char *str, int n, int quotr, - struct ui_file * stream); - -/* Display the host ADDR on STREAM formatted as ``0x%x''. */ -extern void gdb_print_host_address (const void *addr, struct ui_file *stream); - -extern const char *host_address_to_string (const void *addr); - -/* Convert CORE_ADDR to string in platform-specific manner. - This is usually formatted similar to 0x%lx. */ -extern const char *paddress (struct gdbarch *gdbarch, CORE_ADDR addr); - -/* Return a string representation in hexadecimal notation of ADDRESS, - which is suitable for printing. */ - -extern const char *print_core_address (struct gdbarch *gdbarch, - CORE_ADDR address); - -/* Callback hash_f and eq_f for htab_create_alloc or htab_create_alloc_ex. */ - -extern hashval_t core_addr_hash (const void *ap); -extern int core_addr_eq (const void *ap, const void *bp); - -/* %d for LONGEST */ -extern char *plongest (LONGEST l); -/* %u for ULONGEST */ -extern char *pulongest (ULONGEST l); - -extern char *phex (ULONGEST l, int sizeof_l); -extern char *phex_nz (ULONGEST l, int sizeof_l); -extern char *int_string (LONGEST, int, int, int, int); - -/* Convert a CORE_ADDR into a HEX string with leading zeros. - The output from core_addr_to_string() can be passed direct to - string_to_core_addr(). */ -extern const char *core_addr_to_string (const CORE_ADDR addr); -extern const char *core_addr_to_string_nz (const CORE_ADDR addr); -extern CORE_ADDR string_to_core_addr (const char *my_string); - -/* Return a string that contains a number formatted as a hex - string. */ -extern char *hex_string (LONGEST); -extern char *hex_string_custom (LONGEST, int); - -extern void fprintf_symbol_filtered (struct ui_file *, char *, - enum language, int); - -extern void perror_with_name (const char *) ATTRIBUTE_NORETURN; - -extern void print_sys_errmsg (const char *, int); /* From regex.c or libc. BSD 4.4 declares this with the argument type as "const char *" in unistd.h, so we can't declare the argument @@ -634,8 +328,8 @@ extern int info_verbose; extern void set_next_address (struct gdbarch *, CORE_ADDR); -extern void print_address_symbolic (struct gdbarch *, CORE_ADDR, - struct ui_file *, int, char *); +extern int print_address_symbolic (struct gdbarch *, CORE_ADDR, + struct ui_file *, int, char *); extern int build_address_symbolic (struct gdbarch *, CORE_ADDR addr, @@ -651,8 +345,10 @@ extern const char *pc_prefix (CORE_ADDR); /* From source.c */ +/* See openp function definition for their description. */ #define OPF_TRY_CWD_FIRST 0x01 #define OPF_SEARCH_IN_PATH 0x02 +#define OPF_DISABLE_REALPATH 0x04 extern int openp (const char *, int, const char *, int, char **); @@ -662,8 +358,6 @@ extern void mod_path (char *, char **); extern void add_path (char *, char **, int); -extern void directory_command (char *, int); - extern void directory_switch (char *, int); extern char *source_path; @@ -672,9 +366,14 @@ extern void init_source_path (void); /* From exec.c */ +/* Process memory area starting at ADDR with length SIZE. Area is readable iff + READ is non-zero, writable if WRITE is non-zero, executable if EXEC is + non-zero. Area is possibly changed against its original file based copy if + MODIFIED is non-zero. DATA is passed without changes from a caller. */ + typedef int (*find_memory_region_ftype) (CORE_ADDR addr, unsigned long size, int read, int write, int exec, - void *data); + int modified, void *data); /* Take over the 'find_mapped_memory' vector from exec.c. */ extern void exec_set_find_memory_regions @@ -748,6 +447,35 @@ extern struct command_line *read_command_lines_1 (char * (*) (void), int, extern void free_command_lines (struct command_line **); +/* Parameters of the "info proc" command. */ + +enum info_proc_what + { + /* Display the default cmdline, cwd and exe outputs. */ + IP_MINIMAL, + + /* Display `info proc mappings'. */ + IP_MAPPINGS, + + /* Display `info proc status'. */ + IP_STATUS, + + /* Display `info proc stat'. */ + IP_STAT, + + /* Display `info proc cmdline'. */ + IP_CMDLINE, + + /* Display `info proc exe'. */ + IP_EXE, + + /* Display `info proc cwd'. */ + IP_CWD, + + /* Display all of the above. */ + IP_ALL + }; + /* String containing the current directory (what getwd would return). */ extern char *current_directory; @@ -828,11 +556,6 @@ enum val_prettyprint extern int longest_to_int (LONGEST); -/* Assorted functions we can declare, now that const and volatile are - defined. */ - -extern char *savestring (const char *, size_t); - /* Utility macros to allocate typed memory. Avoids errors like: struct foo *foo = xmalloc (sizeof struct bar); and memset (foo, sizeof (struct foo), 0). */ @@ -842,49 +565,6 @@ extern char *savestring (const char *, size_t); #include "common-utils.h" -extern int parse_escape (struct gdbarch *, char **); - -/* Message to be printed before the error message, when an error occurs. */ - -extern char *error_pre_print; - -/* Message to be printed before the error message, when an error occurs. */ - -extern char *quit_pre_print; - -/* Message to be printed before the warning message, when a warning occurs. */ - -extern char *warning_pre_print; - -extern void verror (const char *fmt, va_list ap) - ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 0); - -extern void error (const char *fmt, ...) - ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2); - -extern void error_stream (struct ui_file *) ATTRIBUTE_NORETURN; - -extern void vfatal (const char *fmt, va_list ap) - ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 0); - -extern void fatal (const char *fmt, ...) - ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2); - -extern void internal_verror (const char *file, int line, const char *, - va_list ap) - ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0); - -extern void internal_vwarning (const char *file, int line, - const char *, va_list ap) - ATTRIBUTE_PRINTF (3, 0); - -extern void internal_warning (const char *file, int line, - const char *, ...) ATTRIBUTE_PRINTF (3, 4); - -extern void warning (const char *, ...) ATTRIBUTE_PRINTF (1, 2); - -extern void vwarning (const char *, va_list args) ATTRIBUTE_PRINTF (1, 0); - /* List of known OS ABIs. If you change this, make sure to update the table in osabi.c. */ enum gdb_osabi @@ -915,6 +595,9 @@ enum gdb_osabi GDB_OSABI_DICOS, GDB_OSABI_DARWIN, GDB_OSABI_SYMBIAN, + GDB_OSABI_OPENVMS, + GDB_OSABI_LYNXOS178, + GDB_OSABI_NEWLIB, GDB_OSABI_INVALID /* keep this last */ }; @@ -932,12 +615,6 @@ enum gdb_osabi #ifdef HAVE_STDLIB_H #include #endif -#ifndef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#endif #ifndef atof @@ -1072,38 +749,13 @@ extern void (*deprecated_call_command_hook) (struct cmd_list_element * c, extern void (*deprecated_set_hook) (struct cmd_list_element * c); -extern void (*deprecated_error_begin_hook) (void); - extern int (*deprecated_ui_load_progress_hook) (const char *section, unsigned long num); - /* Inhibit window interface if non-zero. */ extern int use_windows; -/* Definitions of filename-related things. */ - -/* Host specific things. */ - -#ifdef __MSDOS__ -# define CANT_FORK -# define GLOBAL_CURDIR -# define DIRNAME_SEPARATOR ';' -#endif - -#if !defined (__CYGWIN__) && defined (_WIN32) -# define DIRNAME_SEPARATOR ';' -#endif - -#ifndef DIRNAME_SEPARATOR -#define DIRNAME_SEPARATOR ':' -#endif - -#ifndef SLASH_STRING -#define SLASH_STRING "/" -#endif - /* Provide default definitions of PIDGET, TIDGET, and MERGEPID. The name ``TIDGET'' is a historical accident. Many uses of TIDGET in the code actually refer to a lightweight process id, i.e, @@ -1133,42 +785,8 @@ extern int use_windows; #define ISATTY(FP) (isatty (fileno (FP))) #endif -/* Ensure that V is aligned to an N byte boundary (B's assumed to be a - power of 2). Round up/down when necessary. Examples of correct - use include: - - addr = align_up (addr, 8); -- VALUE needs 8 byte alignment - write_memory (addr, value, len); - addr += len; - - and: - - sp = align_down (sp - len, 16); -- Keep SP 16 byte aligned - write_memory (sp, value, len); - - Note that uses such as: - - write_memory (addr, value, len); - addr += align_up (len, 8); - - and: - - sp -= align_up (len, 8); - write_memory (sp, value, len); - - are typically not correct as they don't ensure that the address (SP - or ADDR) is correctly aligned (relying on previous alignment to - keep things right). This is also why the methods are called - "align_..." instead of "round_..." as the latter reads better with - this incorrect coding style. */ - -extern ULONGEST align_up (ULONGEST v, int n); -extern ULONGEST align_down (ULONGEST v, int n); - -/* Allocation and deallocation functions for the libiberty hash table - which use obstacks. */ -void *hashtab_obstack_allocate (void *data, size_t size, size_t count); -void dummy_obstack_deallocate (void *object, void *data); +/* A width that can achieve a better legibility for GDB MI mode. */ +#define GDB_MI_MSG_WIDTH 80 /* From progspace.c */ @@ -1184,4 +802,6 @@ enum block_enum FIRST_LOCAL_BLOCK = 2 }; +#include "utils.h" + #endif /* #ifndef DEFS_H */ diff --git a/contrib/gdb-7/gdb/demangle.c b/contrib/gdb-7/gdb/demangle.c index fa6f4a635d..1cbfe9909a 100644 --- a/contrib/gdb-7/gdb/demangle.c +++ b/contrib/gdb-7/gdb/demangle.c @@ -1,7 +1,6 @@ /* Basic C++ demangling support for GDB. - Copyright (C) 1991-1996, 1998-2001, 2003, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1991-2013 Free Software Foundation, Inc. Written by Fred Fish at Cygnus Support. diff --git a/contrib/gdb-7/gdb/dfp.c b/contrib/gdb-7/gdb/dfp.c index ae6204b562..42cba14c79 100644 --- a/contrib/gdb-7/gdb/dfp.c +++ b/contrib/gdb-7/gdb/dfp.c @@ -1,6 +1,6 @@ /* Decimal floating point support for GDB. - Copyright 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2007-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/dfp.h b/contrib/gdb-7/gdb/dfp.h index 2789b31da6..6c31351971 100644 --- a/contrib/gdb-7/gdb/dfp.h +++ b/contrib/gdb-7/gdb/dfp.h @@ -1,6 +1,6 @@ /* Decimal floating point support for GDB. - Copyright 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2007-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/dictionary.c b/contrib/gdb-7/gdb/dictionary.c index 00c72e8a8a..183e1ca7fe 100644 --- a/contrib/gdb-7/gdb/dictionary.c +++ b/contrib/gdb-7/gdb/dictionary.c @@ -1,6 +1,6 @@ /* Routines for name->symbol lookups in GDB. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. Contributed by David Carlton and by Kealia, Inc. @@ -498,6 +498,22 @@ dict_add_symbol (struct dictionary *dict, struct symbol *sym) (DICT_VECTOR (dict))->add_symbol (dict, sym); } +/* Utility to add a list of symbols to a dictionary. + DICT must be an expandable dictionary. */ + +void +dict_add_pending (struct dictionary *dict, const struct pending *symbol_list) +{ + const struct pending *list; + int i; + + for (list = symbol_list; list != NULL; list = list->next) + { + for (i = 0; i < list->nsyms; ++i) + dict_add_symbol (dict, list->symbol[i]); + } +} + /* Initialize ITERATOR to point at the first symbol in DICT, and return that first symbol, or NULL if DICT is empty. */ @@ -800,6 +816,17 @@ dict_hash (const char *string0) hash = 0; while (*string) { + /* Ignore "TKB" suffixes. + + These are used by Ada for subprograms implementing a task body. + For instance for a task T inside package Pck, the name of the + subprogram implementing T's body is `pck__tTKB'. We need to + ignore the "TKB" suffix because searches for this task body + subprogram are going to be performed using `pck__t' (the encoded + version of the natural name `pck.t'). */ + if (strcmp (string, "TKB") == 0) + return hash; + switch (*string) { case '$': diff --git a/contrib/gdb-7/gdb/dictionary.h b/contrib/gdb-7/gdb/dictionary.h index 1d58fabfe9..9e1c47c041 100644 --- a/contrib/gdb-7/gdb/dictionary.h +++ b/contrib/gdb-7/gdb/dictionary.h @@ -1,6 +1,6 @@ /* Routines for name->symbol lookups in GDB. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. Contributed by David Carlton and by Kealia, Inc. @@ -85,6 +85,11 @@ extern void dict_free (struct dictionary *dict); extern void dict_add_symbol (struct dictionary *dict, struct symbol *sym); +/* Utility to add a list of symbols to a dictionary. */ + +extern void dict_add_pending (struct dictionary *dict, + const struct pending *symbol_list); + /* Is the dictionary empty? */ extern int dict_empty (struct dictionary *dict); diff --git a/contrib/gdb-7/gdb/disasm.c b/contrib/gdb-7/gdb/disasm.c index 89bd82918c..e643c2d9e3 100644 --- a/contrib/gdb-7/gdb/disasm.c +++ b/contrib/gdb-7/gdb/disasm.c @@ -1,6 +1,6 @@ /* Disassemble support for GDB. - Copyright (C) 2000-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -97,7 +97,7 @@ static int dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, struct disassemble_info * di, CORE_ADDR low, CORE_ADDR high, - int how_many, int flags, struct ui_stream *stb) + int how_many, int flags, struct ui_file *stb) { int num_displayed = 0; CORE_ADDR pc; @@ -122,7 +122,9 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, num_displayed++; } ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - ui_out_text (uiout, pc_prefix (pc)); + + if ((flags & DISASSEMBLY_OMIT_PC) == 0) + ui_out_text (uiout, pc_prefix (pc)); ui_out_field_core_addr (uiout, "address", gdbarch, pc); if (!build_address_symbolic (gdbarch, pc, 0, &name, &offset, &filename, @@ -145,7 +147,7 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, if (name != NULL) xfree (name); - ui_file_rewind (stb->stream); + ui_file_rewind (stb); if (flags & DISASSEMBLY_RAW_INSN) { CORE_ADDR old_pc = pc; @@ -155,9 +157,9 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, /* Build the opcodes using a temporary stream so we can write them out in a single go for the MI. */ - struct ui_stream *opcode_stream = ui_out_stream_new (uiout); + struct ui_file *opcode_stream = mem_fileopen (); struct cleanup *cleanups = - make_cleanup_ui_out_stream_delete (opcode_stream); + make_cleanup_ui_file_delete (opcode_stream); pc += gdbarch_print_insn (gdbarch, pc, di); for (;old_pc < pc; old_pc++) @@ -165,7 +167,7 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, status = (*di->read_memory_func) (old_pc, &data, 1, di); if (status != 0) (*di->memory_error_func) (status, old_pc, di); - fprintf_filtered (opcode_stream->stream, "%s%02x", + fprintf_filtered (opcode_stream, "%s%02x", spacer, (unsigned) data); spacer = " "; } @@ -177,7 +179,7 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, else pc += gdbarch_print_insn (gdbarch, pc, di); ui_out_field_stream (uiout, "inst", stb); - ui_file_rewind (stb->stream); + ui_file_rewind (stb); do_cleanups (ui_out_chain); ui_out_text (uiout, "\n"); } @@ -195,7 +197,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, struct linetable_entry *le, CORE_ADDR low, CORE_ADDR high, struct symtab *symtab, - int how_many, int flags, struct ui_stream *stb) + int how_many, int flags, struct ui_file *stb) { int newlines = 0; struct dis_line_entry *mle; @@ -204,10 +206,14 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, int out_of_order = 0; int next_line = 0; int num_displayed = 0; + enum print_source_lines_flags psl_flags = 0; struct cleanup *ui_out_chain; struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0); struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0); + if (flags & DISASSEMBLY_FILENAME) + psl_flags |= PRINT_SOURCE_LINES_FILENAME; + mle = (struct dis_line_entry *) alloca (nlines * sizeof (struct dis_line_entry)); @@ -275,7 +281,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, ui_out_tuple_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line"); - print_source_lines (symtab, next_line, mle[i].line + 1, 0); + print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags); } else { @@ -289,7 +295,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line"); print_source_lines (symtab, next_line, next_line + 1, - 0); + psl_flags); ui_out_list_chain_line = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn"); @@ -301,7 +307,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, ui_out_tuple_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line"); - print_source_lines (symtab, next_line, mle[i].line + 1, 0); + print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags); } } else @@ -309,7 +315,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, ui_out_tuple_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line"); - print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0); + print_source_lines (symtab, mle[i].line, mle[i].line + 1, psl_flags); } next_line = mle[i].line + 1; @@ -342,7 +348,7 @@ static void do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout, struct disassemble_info * di, CORE_ADDR low, CORE_ADDR high, - int how_many, int flags, struct ui_stream *stb) + int how_many, int flags, struct ui_file *stb) { int num_displayed = 0; struct cleanup *ui_out_chain; @@ -402,9 +408,9 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout, char *file_string, int flags, int how_many, CORE_ADDR low, CORE_ADDR high) { - struct ui_stream *stb = ui_out_stream_new (uiout); - struct cleanup *cleanups = make_cleanup_ui_out_stream_delete (stb); - struct disassemble_info di = gdb_disassemble_info (gdbarch, stb->stream); + struct ui_file *stb = mem_fileopen (); + struct cleanup *cleanups = make_cleanup_ui_file_delete (stb); + struct disassemble_info di = gdb_disassemble_info (gdbarch, stb); /* To collect the instruction outputted from opcodes. */ struct symtab *symtab = NULL; struct linetable_entry *le = NULL; diff --git a/contrib/gdb-7/gdb/disasm.h b/contrib/gdb-7/gdb/disasm.h index 646ee8eeb3..3743ccc916 100644 --- a/contrib/gdb-7/gdb/disasm.h +++ b/contrib/gdb-7/gdb/disasm.h @@ -1,5 +1,5 @@ /* Disassemble support for GDB. - Copyright (C) 2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +22,8 @@ #define DISASSEMBLY_SOURCE (0x1 << 0) #define DISASSEMBLY_RAW_INSN (0x1 << 1) #define DISASSEMBLY_OMIT_FNAME (0x1 << 2) +#define DISASSEMBLY_FILENAME (0x1 << 3) +#define DISASSEMBLY_OMIT_PC (0x1 << 4) struct ui_out; struct ui_file; diff --git a/contrib/gdb-7/gdb/doc/agentexpr.texi b/contrib/gdb-7/gdb/doc/agentexpr.texi index d0f6f15cc3..ab243cc77b 100644 --- a/contrib/gdb-7/gdb/doc/agentexpr.texi +++ b/contrib/gdb-7/gdb/doc/agentexpr.texi @@ -7,7 +7,7 @@ @c This file is part of the GDB manual. @c -@c Copyright (C) 2003-2006, 2009-2012 Free Software Foundation, Inc. +@c Copyright (C) 2003-2013 Free Software Foundation, Inc. @c @c See the file gdb.texinfo for copying conditions. @@ -493,6 +493,23 @@ Record the bytes at @var{addr} in a trace buffer, for later retrieval by GDB. Stop at either the first zero byte, or when @var{size} bytes have been recorded, whichever occurs first. +@item @code{printf} (0x34) @var{numargs} @var{string} @result{} +Do a formatted print, in the style of the C function @code{printf}). +The value of @var{numargs} is the number of arguments to expect on the +stack, while @var{string} is the format string, prefixed with a +two-byte length. The last byte of the string must be zero, and is +included in the length. The format string includes escaped sequences +just as it appears in C source, so for instance the format string +@code{"\t%d\n"} is six characters long, and the output will consist of +a tab character, a decimal number, and a newline. At the top of the +stack, above the values to be printed, this bytecode will pop a +``function'' and ``channel''. If the function is nonzero, then the +target may treat it as a function and call it, passing the channel as +a first argument, as with the C function @code{fprintf}. If the +function is zero, then the target may simply call a standard formatted +print function of its choice. In all, this bytecode pops 2 + +@var{numargs} stack elements, and pushes nothing. + @item @code{end} (0x27): @result{} Stop executing bytecode; the result should be the top element of the stack. If the purpose of the expression was to compute an lvalue or a diff --git a/contrib/gdb-7/gdb/doc/all-cfg.texi b/contrib/gdb-7/gdb/doc/all-cfg.texi index 4f5a65e97c..75f3033102 100644 --- a/contrib/gdb-7/gdb/doc/all-cfg.texi +++ b/contrib/gdb-7/gdb/doc/all-cfg.texi @@ -1,7 +1,6 @@ @c GDB MANUAL configuration file. @c -@c Copyright (C) 1993, 1995, 1999, 2002, 2011-2012 Free Software -@c Foundation, Inc. +@c Copyright (C) 1993-2013 Free Software Foundation, Inc. @c @c NOTE: While the GDB manual is configurable (by changing these @c switches), its configuration is ***NOT*** automatically tied in to @@ -32,9 +31,6 @@ @c Name of GDB program. Used also for (gdb) prompt string. @set GDBP gdb @c -@c Name of GDBTUI program. -@set GDBTUI gdbtui -@c @c Name of GDB product. Used in running text. @set GDBN @sc{gdb} @c diff --git a/contrib/gdb-7/gdb/doc/annotate.texinfo b/contrib/gdb-7/gdb/doc/annotate.texinfo index 20f6eb6abb..05e1409ea6 100644 --- a/contrib/gdb-7/gdb/doc/annotate.texinfo +++ b/contrib/gdb-7/gdb/doc/annotate.texinfo @@ -27,8 +27,7 @@ @c cost. Having a smaller cheaper manual helps the GNU Press with its sales. @copying -Copyright @copyright{} 1994-1995, 2000-2001, 2003-2005, 2007-2012 Free -Software Foundation, Inc. +Copyright @copyright{} 1994-2013 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or diff --git a/contrib/gdb-7/gdb/doc/gdb.texinfo b/contrib/gdb-7/gdb/doc/gdb.texinfo index 95ae000485..d4fec54e78 100644 --- a/contrib/gdb-7/gdb/doc/gdb.texinfo +++ b/contrib/gdb-7/gdb/doc/gdb.texinfo @@ -1,5 +1,5 @@ \input texinfo @c -*-texinfo-*- -@c Copyright (C) 1988-1996, 1998-2012 Free Software Foundation, Inc. +@c Copyright (C) 1988-2013 Free Software Foundation, Inc. @c @c %**start of header @c makeinfo ignores cmds prev to setfilename, so its arg cannot make use @@ -18,13 +18,16 @@ @end iftex @finalout -@syncodeindex ky cp -@syncodeindex tp cp +@c To avoid file-name clashes between index.html and Index.html, when +@c the manual is produced on a Posix host and then moved to a +@c case-insensitive filesystem (e.g., MS-Windows), we separate the +@c indices into two: Concept Index and all the rest. +@syncodeindex ky fn +@syncodeindex tp fn @c readline appendices use @vindex, @findex and @ftable, @c annotate.texi and gdbmi use @findex. -@syncodeindex vr cp -@syncodeindex fn cp +@syncodeindex vr fn @c !!set GDB manual's edition---not the same as GDB version! @c This is updated by GNU Press. @@ -43,9 +46,7 @@ @end direntry @copying -Copyright @copyright{} 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, -1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 -Free Software Foundation, Inc. +Copyright @copyright{} 1988-2013 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -114,7 +115,7 @@ This is the @value{EDITION} Edition, for @value{GDBN} @end ifset Version @value{GDBVN}. -Copyright (C) 1988-2010 Free Software Foundation, Inc. +Copyright (C) 1988-2013 Free Software Foundation, Inc. This edition of the GDB manual is dedicated to the memory of Fred Fish. Fred was a long-standing contributor to GDB and to Free @@ -154,6 +155,7 @@ software in general. We will miss him. * GDB/MI:: @value{GDBN}'s Machine Interface. * Annotations:: @value{GDBN}'s annotation interface. * JIT Interface:: Using the JIT debugging interface. +* In-Process Agent:: In-Process Agent * GDB Bugs:: Reporting bugs in @value{GDBN} @@ -180,7 +182,9 @@ software in general. We will miss him. * Copying:: GNU General Public License says how you can copy and share GDB * GNU Free Documentation License:: The license for this documentation -* Index:: Index +* Concept Index:: Index of @value{GDBN} concepts +* Command and Variable Index:: Index of @value{GDBN} commands, variables, + functions, and Python data types @end menu @end ifnottex @@ -242,6 +246,7 @@ using either the Apple/NeXT or the GNU Objective-C runtime. @menu * Free Software:: Freely redistributable software +* Free Documentation:: Free Software Needs Free Documentation * Contributors:: Contributors to GDB @end menu @@ -261,6 +266,7 @@ Fundamentally, the General Public License is a license which says that you have these freedoms and that you cannot take these freedoms away from anyone else. +@node Free Documentation @unnumberedsec Free Software Needs Free Documentation The biggest deficiency in the free software community today is not in @@ -989,6 +995,22 @@ also be interleaved with @samp{-command} as required. -x setbreakpoints -ex 'run' a.out @end smallexample +@item -init-command @var{file} +@itemx -ix @var{file} +@cindex @code{--init-command} +@cindex @code{-ix} +Execute commands from file @var{file} before loading the inferior (but +after loading gdbinit files). +@xref{Startup}. + +@item -init-eval-command @var{command} +@itemx -iex @var{command} +@cindex @code{--init-eval-command} +@cindex @code{-iex} +Execute a single @value{GDBN} command before loading the inferior (but +after loading gdbinit files). +@xref{Startup}. + @item -directory @var{directory} @itemx -d @var{directory} @cindex @code{--directory} @@ -1012,14 +1034,42 @@ You can run @value{GDBN} in various alternative modes---for example, in batch mode or quiet mode. @table @code +@anchor{-nx} @item -nx @itemx -n @cindex @code{--nx} @cindex @code{-n} -Do not execute commands found in any initialization files. Normally, -@value{GDBN} executes the commands in these files after all the command -options and arguments have been processed. @xref{Command Files,,Command -Files}. +Do not execute commands found in any initialization file. +There are three init files, loaded in the following order: + +@table @code +@item @file{system.gdbinit} +This is the system-wide init file. +Its location is specified with the @code{--with-system-gdbinit} +configure option (@pxref{System-wide configuration}). +It is loaded first when @value{GDBN} starts, before command line options +have been processed. +@item @file{~/.gdbinit} +This is the init file in your home directory. +It is loaded next, after @file{system.gdbinit}, and before +command options have been processed. +@item @file{./.gdbinit} +This is the init file in the current directory. +It is loaded last, after command line options other than @code{-x} and +@code{-ex} have been processed. Command line options @code{-x} and +@code{-ex} are processed last, after @file{./.gdbinit} has been loaded. +@end table + +For further documentation on startup processing, @xref{Startup}. +For documentation on how to write command files, +@xref{Command Files,,Command Files}. + +@anchor{-nh} +@item -nh +@cindex @code{--nh} +Do not execute commands found in @file{~/.gdbinit}, the init file +in your home directory. +@xref{Startup}. @item -quiet @itemx -silent @@ -1127,13 +1177,6 @@ and a newline. The Emacs-to-@value{GDBN} interface program uses the two @samp{\032} characters as a signal to display the source code for the frame. -@item -epoch -@cindex @code{--epoch} -The Epoch Emacs-@value{GDBN} interface sets this option when it runs -@value{GDBN} as a subprocess. It tells @value{GDBN} to modify its print -routines so as to allow Epoch to display values of expressions in a -separate window. - @item -annotate @var{level} @cindex @code{--annotate} This option sets the @dfn{annotation level} inside @value{GDBN}. Its @@ -1179,10 +1222,9 @@ Run using @var{device} for your program's standard input and output. Activate the @dfn{Text User Interface} when starting. The Text User Interface manages several text windows on the terminal, showing source, assembly, registers and @value{GDBN} command outputs -(@pxref{TUI, ,@value{GDBN} Text User Interface}). Alternatively, the -Text User Interface can be enabled by invoking the program -@samp{@value{GDBTUI}}. Do not use this option if you run @value{GDBN} from -Emacs (@pxref{Emacs, ,Using @value{GDBN} under @sc{gnu} Emacs}). +(@pxref{TUI, ,@value{GDBN} Text User Interface}). Do not use this +option if you run @value{GDBN} from Emacs (@pxref{Emacs, , +Using @value{GDBN} under @sc{gnu} Emacs}). @c @item -xdb @c @cindex @code{--xdb} @@ -1241,18 +1283,30 @@ used when building @value{GDBN}; @pxref{System-wide configuration, ,System-wide configuration and settings}) and executes all the commands in that file. +@anchor{Home Directory Init File} @item Reads the init file (if any) in your home directory@footnote{On DOS/Windows systems, the home directory is the one pointed to by the @code{HOME} environment variable.} and executes all the commands in that file. +@anchor{Option -init-eval-command} +@item +Executes commands and command files specified by the @samp{-iex} and +@samp{-ix} options in their specified order. Usually you should use the +@samp{-ex} and @samp{-x} options instead, but this way you can apply +settings before @value{GDBN} init files get executed and before inferior +gets loaded. + @item Processes command line options and operands. +@anchor{Init File in the Current Directory during Startup} @item Reads and executes the commands from init file (if any) in the current -working directory. This is only done if the current directory is +working directory as long as @samp{set auto-load local-gdbinit} is set to +@samp{on} (@pxref{Init File in the Current Directory}). +This is only done if the current directory is different from your home directory. Thus, you can have more than one init file, one generic in your home directory, and another, specific to the program you are debugging, in the directory where you invoke @@ -1268,18 +1322,16 @@ If you wish to disable the auto-loading during startup, you must do something like the following: @smallexample -$ gdb -ex "set auto-load-scripts off" -ex "file myprogram" +$ gdb -iex "set auto-load python-scripts off" myprogram @end smallexample -The following does not work because the auto-loading is turned off too late: - -@smallexample -$ gdb -ex "set auto-load-scripts off" myprogram -@end smallexample +Option @samp{-ex} does not work because the auto-loading is then turned +off too late. @item -Reads command files specified by the @samp{-x} option. @xref{Command -Files}, for more details about @value{GDBN} command files. +Executes commands and command files specified by the @samp{-ex} and +@samp{-x} options in their specified order. @xref{Command Files}, for +more details about @value{GDBN} command files. @item Reads the command history recorded in the @dfn{history file}. @@ -1303,9 +1355,9 @@ can use @kbd{gdb --help}. The @value{GDBN} init files are normally called @file{.gdbinit}. The DJGPP port of @value{GDBN} uses the name @file{gdb.ini}, due to the limitations of file names imposed by DOS filesystems. The Windows -ports of @value{GDBN} use the standard name, but if they find a -@file{gdb.ini} file, they warn you about that and suggest to rename -the file to the standard name. +port of @value{GDBN} uses the standard name, but if it finds a +@file{gdb.ini} file in your home directory, it warns you about that +and suggests to rename the file to the standard name. @node Quitting GDB @@ -1699,7 +1751,7 @@ commands, and their documentation, for the regular expression specified in @var{args}. It prints out all matches found. For example: @smallexample -apropos reload +apropos alias @end smallexample @noindent @@ -1707,10 +1759,11 @@ results in: @smallexample @c @group -set symbol-reloading -- Set dynamic symbol table reloading - multiple times in one run -show symbol-reloading -- Show dynamic symbol table reloading - multiple times in one run +alias -- Define a new command that is an alias of an existing command +aliases -- Aliases of other commands +d -- Delete some breakpoints or auto-display expressions +del -- Delete some breakpoints or auto-display expressions +delete -- Delete some breakpoints or auto-display expressions @c @end group @end smallexample @@ -1742,8 +1795,9 @@ In addition to @code{help}, you can use the @value{GDBN} commands @code{info} and @code{show} to inquire about the state of your program, or the state of @value{GDBN} itself. Each command supports many topics of inquiry; this manual introduces each of them in the appropriate context. The listings -under @code{info} and under @code{show} in the Index point to -all the sub-commands. @xref{Index}. +under @code{info} and under @code{show} in the Command, Variable, and +Function Index point to all the sub-commands. @xref{Command and Variable +Index}. @c @group @table @code @@ -2229,8 +2283,9 @@ Specify Files}. @table @code @kindex cd @cindex change working directory -@item cd @var{directory} -Set the @value{GDBN} working directory to @var{directory}. +@item cd @r{[}@var{directory}@r{]} +Set the @value{GDBN} working directory to @var{directory}. If not +given, @var{directory} uses @file{'~'}. @kindex pwd @item pwd @@ -2856,6 +2911,7 @@ programs with multiple threads. @xref{Set Watchpoints,,Setting Watchpoints}, for information about watchpoints in programs with multiple threads. +@anchor{set libthread-db-search-path} @table @code @kindex set libthread-db-search-path @cindex search path for @code{libthread_db} @@ -2870,11 +2926,15 @@ macro. On @sc{gnu}/Linux and Solaris systems, @value{GDBN} uses a ``helper'' @code{libthread_db} library to obtain information about threads in the inferior process. @value{GDBN} will use @samp{libthread-db-search-path} -to find @code{libthread_db}. +to find @code{libthread_db}. @value{GDBN} also consults first if inferior +specific thread debugging library loading is enabled +by @samp{set auto-load libthread-db} (@pxref{libthread_db.so.1 file}). A special entry @samp{$sdir} for @samp{libthread-db-search-path} refers to the default system directories that are -normally searched for loading shared libraries. +normally searched for loading shared libraries. The @samp{$sdir} entry +is the only kind not needing to be enabled by @samp{set auto-load libthread-db} +(@pxref{libthread_db.so.1 file}). A special entry @samp{$pdir} for @samp{libthread-db-search-path} refers to the directory from which @code{libpthread} @@ -3301,7 +3361,9 @@ all breakpoints in that range are operated on. * Disabling:: Disabling breakpoints * Conditions:: Break conditions * Break Commands:: Breakpoint command lists +* Dynamic Printf:: Dynamic printf * Save Breakpoints:: How to save breakpoints in a file +* Static Probe Points:: Listing static probe points * Error in Breakpoints:: ``Cannot insert breakpoints'' * Breakpoint-related Warnings:: ``Breakpoint address adjusted...'' @end menu @@ -3485,12 +3547,17 @@ the appropriate shared library is loaded in the future. @end table @noindent -If a breakpoint is conditional, @code{info break} shows the condition on -the line following the affected breakpoint; breakpoint commands, if any, -are listed after that. A pending breakpoint is allowed to have a condition -specified for it. The condition is not parsed for validity until a shared -library is loaded that allows the pending breakpoint to resolve to a -valid location. +If a breakpoint is conditional, there are two evaluation modes: ``host'' and +``target''. If mode is ``host'', breakpoint condition evaluation is done by +@value{GDBN} on the host's side. If it is ``target'', then the condition +is evaluated by the target. The @code{info break} command shows +the condition on the line following the affected breakpoint, together with +its condition evaluation mode in between parentheses. + +Breakpoint commands, if any, are listed after that. A pending breakpoint is +allowed to have a condition specified for it. The condition is not parsed for +validity until a shared library is loaded that allows the pending +breakpoint to resolve to a valid location. @noindent @code{info break} with a breakpoint @@ -3506,6 +3573,11 @@ has been hit. This is especially useful in conjunction with the hits, look at the breakpoint info to see how many times the breakpoint was hit, and then run again, ignoring one less than that number. This will get you quickly to the last hit of that breakpoint. + +@noindent +For a breakpoints with an enable count (xref) greater than 1, +@code{info break} also displays that count. + @end table @value{GDBN} allows you to set any number of breakpoints at the same place in @@ -3682,6 +3754,47 @@ controlling the inferior in all-stop mode, @value{GDBN} behaves as if @code{breakpoint always-inserted} mode is off. @end table +@value{GDBN} handles conditional breakpoints by evaluating these conditions +when a breakpoint breaks. If the condition is true, then the process being +debugged stops, otherwise the process is resumed. + +If the target supports evaluating conditions on its end, @value{GDBN} may +download the breakpoint, together with its conditions, to it. + +This feature can be controlled via the following commands: + +@kindex set breakpoint condition-evaluation +@kindex show breakpoint condition-evaluation +@table @code +@item set breakpoint condition-evaluation host +This option commands @value{GDBN} to evaluate the breakpoint +conditions on the host's side. Unconditional breakpoints are sent to +the target which in turn receives the triggers and reports them back to GDB +for condition evaluation. This is the standard evaluation mode. + +@item set breakpoint condition-evaluation target +This option commands @value{GDBN} to download breakpoint conditions +to the target at the moment of their insertion. The target +is responsible for evaluating the conditional expression and reporting +breakpoint stop events back to @value{GDBN} whenever the condition +is true. Due to limitations of target-side evaluation, some conditions +cannot be evaluated there, e.g., conditions that depend on local data +that is only known to the host. Examples include +conditional expressions involving convenience variables, complex types +that cannot be handled by the agent expression parser and expressions +that are too long to be sent over to the target, specially when the +target is a remote system. In these cases, the conditions will be +evaluated by @value{GDBN}. + +@item set breakpoint condition-evaluation auto +This is the default mode. If the target supports evaluating breakpoint +conditions on its end, @value{GDBN} will download breakpoint conditions to +the target (limitations mentioned previously apply). If the target does +not support breakpoint condition evaluation, then @value{GDBN} will fallback +to evaluating all these conditions on the host's side. +@end table + + @cindex negative breakpoint numbers @cindex internal @value{GDBN} breakpoints @value{GDBN} itself sometimes sets breakpoints in your program for @@ -4114,6 +4227,37 @@ and @sc{gnu}/Linux. A call to @code{vfork}. This is currently only available for HP-UX and @sc{gnu}/Linux. +@item load @r{[}regexp@r{]} +@itemx unload @r{[}regexp@r{]} +The loading or unloading of a shared library. If @var{regexp} is +given, then the catchpoint will stop only if the regular expression +matches one of the affected libraries. + +@item signal @r{[}@var{signal}@dots{} @r{|} @samp{all}@r{]} +The delivery of a signal. + +With no arguments, this catchpoint will catch any signal that is not +used internally by @value{GDBN}, specifically, all signals except +@samp{SIGTRAP} and @samp{SIGINT}. + +With the argument @samp{all}, all signals, including those used by +@value{GDBN}, will be caught. This argument cannot be used with other +signal names. + +Otherwise, the arguments are a list of signal names as given to +@code{handle} (@pxref{Signals}). Only signals specified in this list +will be caught. + +One reason that @code{catch signal} can be more useful than +@code{handle} is that you can attach commands and conditions to the +catchpoint. + +When a signal is caught by a catchpoint, the signal's @code{stop} and +@code{print} settings, as specified by @code{handle}, are ignored. +However, whether the signal is still delivered to the inferior depends +on the @code{pass} setting; this can be changed in the catchpoint's +commands. + @end table @item tcatch @var{event} @@ -4247,8 +4391,8 @@ do not know which numbers to use. Disabling and enabling a breakpoint that has multiple locations affects all of its locations. -A breakpoint, watchpoint, or catchpoint can have any of four different -states of enablement: +A breakpoint, watchpoint, or catchpoint can have any of several +different states of enablement: @itemize @bullet @item @@ -4260,6 +4404,9 @@ Disabled. The breakpoint has no effect on your program. Enabled once. The breakpoint stops your program, but then becomes disabled. @item +Enabled for a count. The breakpoint stops your program for the next +N times, then becomes disabled. +@item Enabled for deletion. The breakpoint stops your program, but immediately after it does so it is deleted permanently. A breakpoint set with the @code{tbreak} command starts out in this state. @@ -4287,6 +4434,14 @@ become effective once again in stopping your program. Enable the specified breakpoints temporarily. @value{GDBN} disables any of these breakpoints immediately after stopping your program. +@item enable @r{[}breakpoints@r{]} count @var{count} @var{range}@dots{} +Enable the specified breakpoints temporarily. @value{GDBN} records +@var{count} with each of the specified breakpoints, and decrements a +breakpoint's count when it is hit. When any count reaches 0, +@value{GDBN} disables that breakpoint. If a breakpoint has an ignore +count (@pxref{Conditions, ,Break Conditions}), that will be +decremented to 0 before @var{count} is affected. + @item enable @r{[}breakpoints@r{]} delete @var{range}@dots{} Enable the specified breakpoints to work once, then die. @value{GDBN} deletes any of these breakpoints as soon as your program stops there. @@ -4341,6 +4496,19 @@ conditions for the purpose of performing side effects when a breakpoint is reached (@pxref{Break Commands, ,Breakpoint Command Lists}). +Breakpoint conditions can also be evaluated on the target's side if +the target supports it. Instead of evaluating the conditions locally, +@value{GDBN} encodes the expression into an agent expression +(@pxref{Agent Expressions}) suitable for execution on the target, +independently of @value{GDBN}. Global variables become raw memory +locations, locals become stack accesses, and so forth. + +In this case, @value{GDBN} will only be notified of a breakpoint trigger +when its condition evaluates to true. This mechanism may provide faster +response times depending on the performance characteristics of the target +since it does not need to keep @value{GDBN} informed about +every breakpoint trigger, even those with false conditions. + Break conditions can be specified when a breakpoint is set, by using @samp{if} in the arguments to the @code{break} command. @xref{Set Breaks, ,Setting Breakpoints}. They can also be changed at any time @@ -4506,6 +4674,114 @@ cont end @end smallexample +@node Dynamic Printf +@subsection Dynamic Printf + +@cindex dynamic printf +@cindex dprintf +The dynamic printf command @code{dprintf} combines a breakpoint with +formatted printing of your program's data to give you the effect of +inserting @code{printf} calls into your program on-the-fly, without +having to recompile it. + +In its most basic form, the output goes to the GDB console. However, +you can set the variable @code{dprintf-style} for alternate handling. +For instance, you can ask to format the output by calling your +program's @code{printf} function. This has the advantage that the +characters go to the program's output device, so they can recorded in +redirects to files and so forth. + +If you are doing remote debugging with a stub or agent, you can also +ask to have the printf handled by the remote agent. In addition to +ensuring that the output goes to the remote program's device along +with any other output the program might produce, you can also ask that +the dprintf remain active even after disconnecting from the remote +target. Using the stub/agent is also more efficient, as it can do +everything without needing to communicate with @value{GDBN}. + +@table @code +@kindex dprintf +@item dprintf @var{location},@var{template},@var{expression}[,@var{expression}@dots{}] +Whenever execution reaches @var{location}, print the values of one or +more @var{expressions} under the control of the string @var{template}. +To print several values, separate them with commas. + +@item set dprintf-style @var{style} +Set the dprintf output to be handled in one of several different +styles enumerated below. A change of style affects all existing +dynamic printfs immediately. (If you need individual control over the +print commands, simply define normal breakpoints with +explicitly-supplied command lists.) + +@item gdb +@kindex dprintf-style gdb +Handle the output using the @value{GDBN} @code{printf} command. + +@item call +@kindex dprintf-style call +Handle the output by calling a function in your program (normally +@code{printf}). + +@item agent +@kindex dprintf-style agent +Have the remote debugging agent (such as @code{gdbserver}) handle +the output itself. This style is only available for agents that +support running commands on the target. + +@item set dprintf-function @var{function} +Set the function to call if the dprintf style is @code{call}. By +default its value is @code{printf}. You may set it to any expression. +that @value{GDBN} can evaluate to a function, as per the @code{call} +command. + +@item set dprintf-channel @var{channel} +Set a ``channel'' for dprintf. If set to a non-empty value, +@value{GDBN} will evaluate it as an expression and pass the result as +a first argument to the @code{dprintf-function}, in the manner of +@code{fprintf} and similar functions. Otherwise, the dprintf format +string will be the first argument, in the manner of @code{printf}. + +As an example, if you wanted @code{dprintf} output to go to a logfile +that is a standard I/O stream assigned to the variable @code{mylog}, +you could do the following: + +@example +(gdb) set dprintf-style call +(gdb) set dprintf-function fprintf +(gdb) set dprintf-channel mylog +(gdb) dprintf 25,"at line 25, glob=%d\n",glob +Dprintf 1 at 0x123456: file main.c, line 25. +(gdb) info break +1 dprintf keep y 0x00123456 in main at main.c:25 + call (void) fprintf (mylog,"at line 25, glob=%d\n",glob) + continue +(gdb) +@end example + +Note that the @code{info break} displays the dynamic printf commands +as normal breakpoint commands; you can thus easily see the effect of +the variable settings. + +@item set disconnected-dprintf on +@itemx set disconnected-dprintf off +@kindex set disconnected-dprintf +Choose whether @code{dprintf} commands should continue to run if +@value{GDBN} has disconnected from the target. This only applies +if the @code{dprintf-style} is @code{agent}. + +@item show disconnected-dprintf off +@kindex show disconnected-dprintf +Show the current choice for disconnected @code{dprintf}. + +@end table + +@value{GDBN} does not check the validity of function and channel, +relying on you to supply values that are meaningful for the contexts +in which they are being used. For instance, the function and channel +may be the values of local variables, but if that is the case, then +all enabled dynamic prints must be at locations within the scope of +those locals. If evaluation fails, @value{GDBN} will report an error. + @node Save Breakpoints @subsection How to save breakpoints to a file @@ -4531,6 +4807,69 @@ and remove the breakpoint definitions you're not interested in, or that can no longer be recreated. @end table +@node Static Probe Points +@subsection Static Probe Points + +@cindex static probe point, SystemTap +@value{GDBN} supports @dfn{SDT} probes in the code. @acronym{SDT} stands +for Statically Defined Tracing, and the probes are designed to have a tiny +runtime code and data footprint, and no dynamic relocations. They are +usable from assembly, C and C@t{++} languages. See +@uref{http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation} +for a good reference on how the @acronym{SDT} probes are implemented. + +Currently, @code{SystemTap} (@uref{http://sourceware.org/systemtap/}) +@acronym{SDT} probes are supported on ELF-compatible systems. See +@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps} +for more information on how to add @code{SystemTap} @acronym{SDT} probes +in your applications. + +@cindex semaphores on static probe points +Some probes have an associated semaphore variable; for instance, this +happens automatically if you defined your probe using a DTrace-style +@file{.d} file. If your probe has a semaphore, @value{GDBN} will +automatically enable it when you specify a breakpoint using the +@samp{-probe-stap} notation. But, if you put a breakpoint at a probe's +location by some other method (e.g., @code{break file:line}), then +@value{GDBN} will not automatically set the semaphore. + +You can examine the available static static probes using @code{info +probes}, with optional arguments: + +@table @code +@kindex info probes +@item info probes stap @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]} +If given, @var{provider} is a regular expression used to match against provider +names when selecting which probes to list. If omitted, probes by all +probes from all providers are listed. + +If given, @var{name} is a regular expression to match against probe names +when selecting which probes to list. If omitted, probe names are not +considered when deciding whether to display them. + +If given, @var{objfile} is a regular expression used to select which +object files (executable or shared libraries) to examine. If not +given, all object files are considered. + +@item info probes all +List the available static probes, from all types. +@end table + +@vindex $_probe_arg@r{, convenience variable} +A probe may specify up to twelve arguments. These are available at the +point at which the probe is defined---that is, when the current PC is +at the probe's location. The arguments are available using the +convenience variables (@pxref{Convenience Vars}) +@code{$_probe_arg0}@dots{}@code{$_probe_arg11}. Each probe argument is +an integer of the appropriate size; types are not preserved. The +convenience variable @code{$_probe_argc} holds the number of arguments +at the current probe point. + +These variables are always available, but attempts to access them at +any location other than a probe point will cause @value{GDBN} to give +an error message. + + @c @ifclear BARETARGET @node Error in Breakpoints @subsection ``Cannot insert breakpoints'' @@ -4688,7 +5027,7 @@ called within the line. Also, the @code{step} command only enters a function if there is line number information for the function. Otherwise it acts like the @code{next} command. This avoids problems when using @code{cc -gl} -on MIPS machines. Previously, @code{step} entered subroutines if there +on @acronym{MIPS} machines. Previously, @code{step} entered subroutines if there was any debugging information about the routine. @item step @var{count} @@ -4824,7 +5163,7 @@ invocations have returned. @kindex advance @var{location} -@itemx advance @var{location} +@item advance @var{location} Continue running the program up to the given @var{location}. An argument is required, which should be of one of the forms described in @ref{Specify Location}. @@ -5011,6 +5350,10 @@ Similar, but print information only about the specified signal number. @code{info handle} is an alias for @code{info signals}. +@item catch signal @r{[}@var{signal}@dots{} @r{|} @samp{all}@r{]} +Set a catchpoint for the indicated signals. @xref{Set Catchpoints}, +for details about this command. + @kindex handle @item handle @var{signal} @r{[}@var{keywords}@dots{}@r{]} Change the way @value{GDBN} handles signal @var{signal}. @var{signal} @@ -5719,7 +6062,7 @@ function invocation, you end up at the beginning. @kindex set exec-direction @item set exec-direction Set the direction of target execution. -@itemx set exec-direction reverse +@item set exec-direction reverse @cindex execute forward or backward in time @value{GDBN} will perform all execution commands in reverse, until the exec-direction mode is changed to ``forward''. Affected commands include @@ -5774,16 +6117,40 @@ For architecture environments that support process record and replay, @table @code @kindex target record +@kindex target record-full +@kindex target record-btrace @kindex record +@kindex record full +@kindex record btrace @kindex rec -@item target record -This command starts the process record and replay target. The process -record and replay target can only debug a process that is already -running. Therefore, you need first to start the process with the -@kbd{run} or @kbd{start} commands, and then start the recording with -the @kbd{target record} command. +@kindex rec full +@kindex rec btrace +@item record @var{method} +This command starts the process record and replay target. The +recording method can be specified as parameter. Without a parameter +the command uses the @code{full} recording method. The following +recording methods are available: + +@table @code +@item full +Full record/replay recording using @value{GDBN}'s software record and +replay implementation. This method allows replaying and reverse +execution. -Both @code{record} and @code{rec} are aliases of @code{target record}. +@item btrace +Hardware-supported instruction recording. This method does not allow +replaying and reverse execution. + +This recording method may not be available on all processors. +@end table + +The process record and replay target can only debug a process that is +already running. Therefore, you need first to start the process with +the @kbd{run} or @kbd{start} commands, and then start the recording +with the @kbd{record @var{method}} command. + +Both @code{record @var{method}} and @code{rec @var{method}} are +aliases of @code{target record-@var{method}}. @cindex displaced stepping, and process record and replay Displaced stepping (@pxref{Maintenance Commands,, displaced stepping}) @@ -5794,9 +6161,9 @@ doesn't support displaced stepping. @cindex non-stop mode, and process record and replay @cindex asynchronous execution, and process record and replay If the inferior is in the non-stop mode (@pxref{Non-Stop Mode}) or in -the asynchronous execution mode (@pxref{Background Execution}), the -process record and replay target cannot be started because it doesn't -support these two modes. +the asynchronous execution mode (@pxref{Background Execution}), not +all recording methods are available. The @code{full} recording method +does not support these two modes. @kindex record stop @kindex rec s @@ -5826,14 +6193,17 @@ Save the execution log to a file @file{@var{filename}}. Default filename is @file{gdb_record.@var{process_id}}, where @var{process_id} is the process ID of the inferior. +This command may not be available for all recording methods. + @kindex record restore @item record restore @var{filename} Restore the execution log from a file @file{@var{filename}}. File must have been created with @code{record save}. -@kindex set record insn-number-max -@item set record insn-number-max @var{limit} -Set the limit of instructions to be recorded. Default value is 200000. +@kindex set record full +@item set record full insn-number-max @var{limit} +Set the limit of instructions to be recorded for the @code{full} +recording method. Default value is 200000. If @var{limit} is a positive number, then @value{GDBN} will start deleting instructions from the log once the number of the record @@ -5848,31 +6218,31 @@ If @var{limit} is zero, @value{GDBN} will never delete recorded instructions from the execution log. The number of recorded instructions is unlimited in this case. -@kindex show record insn-number-max -@item show record insn-number-max -Show the limit of instructions to be recorded. +@kindex show record full +@item show record full insn-number-max +Show the limit of instructions to be recorded with the @code{full} +recording method. -@kindex set record stop-at-limit -@item set record stop-at-limit -Control the behavior when the number of recorded instructions reaches -the limit. If ON (the default), @value{GDBN} will stop when the limit -is reached for the first time and ask you whether you want to stop the -inferior or continue running it and recording the execution log. If -you decide to continue recording, each new recorded instruction will -cause the oldest one to be deleted. +@item set record full stop-at-limit +Control the behavior of the @code{full} recording method when the +number of recorded instructions reaches the limit. If ON (the +default), @value{GDBN} will stop when the limit is reached for the +first time and ask you whether you want to stop the inferior or +continue running it and recording the execution log. If you decide +to continue recording, each new recorded instruction will cause the +oldest one to be deleted. If this option is OFF, @value{GDBN} will automatically delete the oldest record to make room for each new one, without asking. -@kindex show record stop-at-limit -@item show record stop-at-limit +@item show record full stop-at-limit Show the current setting of @code{stop-at-limit}. -@kindex set record memory-query -@item set record memory-query +@item set record full memory-query Control the behavior when @value{GDBN} is unable to record memory -changes caused by an instruction. If ON, @value{GDBN} will query -whether to stop the inferior in that case. +changes caused by an instruction for the @code{full} recording method. +If ON, @value{GDBN} will query whether to stop the inferior in that +case. If this option is OFF (the default), @value{GDBN} will automatically ignore the effect of such instructions on memory. Later, when @@ -5880,14 +6250,18 @@ ignore the effect of such instructions on memory. Later, when instruction as not accessible, and it will not affect the replay results. -@kindex show record memory-query -@item show record memory-query +@item show record full memory-query Show the current setting of @code{memory-query}. @kindex info record @item info record -Show various statistics about the state of process record and its -in-memory execution log buffer, including: +Show various statistics about the recording depending on the recording +method: + +@table @code +@item full +For the @code{full} recording method, it shows the state of process +record and its in-memory execution log buffer, including: @itemize @bullet @item @@ -5904,6 +6278,12 @@ Number of instructions contained in the execution log. Maximum number of instructions that may be contained in the execution log. @end itemize +@item btrace +For the @code{btrace} recording method, it shows the number of +instructions that have been recorded and the number of blocks of +sequential control-flow that is formed by the recorded instructions. +@end table + @kindex record delete @kindex rec del @item record delete @@ -5911,6 +6291,116 @@ When record target runs in replay mode (``in the past''), delete the subsequent execution log and begin to record a new execution log starting from the current address. This means you will abandon the previously recorded ``future'' and begin recording a new ``future''. + +@kindex record instruction-history +@kindex rec instruction-history +@item record instruction-history +Disassembles instructions from the recorded execution log. By +default, ten instructions are disassembled. This can be changed using +the @code{set record instruction-history-size} command. Instructions +are printed in execution order. There are several ways to specify +what part of the execution log to disassemble: + +@table @code +@item record instruction-history @var{insn} +Disassembles ten instructions starting from instruction number +@var{insn}. + +@item record instruction-history @var{insn}, +/-@var{n} +Disassembles @var{n} instructions around instruction number +@var{insn}. If @var{n} is preceded with @code{+}, disassembles +@var{n} instructions after instruction number @var{insn}. If +@var{n} is preceded with @code{-}, disassembles @var{n} +instructions before instruction number @var{insn}. + +@item record instruction-history +Disassembles ten more instructions after the last disassembly. + +@item record instruction-history - +Disassembles ten more instructions before the last disassembly. + +@item record instruction-history @var{begin} @var{end} +Disassembles instructions beginning with instruction number +@var{begin} until instruction number @var{end}. The instruction +number @var{end} is not included. +@end table + +This command may not be available for all recording methods. + +@kindex set record +@item set record instruction-history-size +Define how many instructions to disassemble in the @code{record +instruction-history} command. The default value is 10. + +@kindex show record +@item show record instruction-history-size +Show how many instructions to disassemble in the @code{record +instruction-history} command. + +@kindex record function-call-history +@kindex rec function-call-history +@item record function-call-history +Prints the execution history at function granularity. It prints one +line for each sequence of instructions that belong to the same +function giving the name of that function, the source lines +for this instruction sequence (if the @code{/l} modifier is +specified), and the instructions numbers that form the sequence (if +the @code{/i} modifier is specified). + +@smallexample +(@value{GDBP}) @b{list 1, 10} +1 void foo (void) +2 @{ +3 @} +4 +5 void bar (void) +6 @{ +7 ... +8 foo (); +9 ... +10 @} +(@value{GDBP}) @b{record function-call-history /l} +1 foo.c:6-8 bar +2 foo.c:2-3 foo +3 foo.c:9-10 bar +@end smallexample + +By default, ten lines are printed. This can be changed using the +@code{set record function-call-history-size} command. Functions are +printed in execution order. There are several ways to specify what +to print: + +@table @code +@item record function-call-history @var{func} +Prints ten functions starting from function number @var{func}. + +@item record function-call-history @var{func}, +/-@var{n} +Prints @var{n} functions around function number @var{func}. If +@var{n} is preceded with @code{+}, prints @var{n} functions after +function number @var{func}. If @var{n} is preceded with @code{-}, +prints @var{n} functions before function number @var{func}. + +@item record function-call-history +Prints ten more functions after the last ten-line print. + +@item record function-call-history - +Prints ten more functions before the last ten-line print. + +@item record function-call-history @var{begin} @var{end} +Prints functions beginning with function number @var{begin} until +function number @var{end}. The function number @var{end} is not +included. +@end table + +This command may not be available for all recording methods. + +@item set record function-call-history-size +Define how many lines to print in the +@code{record function-call-history} command. The default value is 10. + +@item show record function-call-history-size +Show how many lines to print in the +@code{record function-call-history} command. @end table @@ -6191,6 +6681,24 @@ unlimited. Display the current limit on backtrace levels. @end table +You can control how file names are displayed. + +@table @code +@item set filename-display +@itemx set filename-display relative +@cindex filename-display +Display file names relative to the compilation directory. This is the default. + +@item set filename-display basename +Display only basename of a filename. + +@item set filename-display absolute +Display an absolute filename. + +@item show filename-display +Show the current way to display filenames. +@end table + @node Selection @section Selecting a Frame @@ -6220,7 +6728,7 @@ switches between them. On the SPARC architecture, @code{frame} needs two addresses to select an arbitrary frame: a frame pointer and a stack pointer. -On the MIPS and Alpha architecture, it needs two addresses: a stack +On the @acronym{MIPS} and Alpha architecture, it needs two addresses: a stack pointer and a program counter. On the 29k architecture, it needs three addresses: a register stack @@ -6340,16 +6848,6 @@ Print the local variables of the selected frame, each on a separate line. These are all variables (declared either static or automatic) accessible at the point of execution of the selected frame. -@kindex info catch -@cindex catch exceptions, list active handlers -@cindex exception handlers, how to list -@item info catch -Print a list of all the exception handlers that are active in the -current stack frame at the current point of execution. To see other -exception handlers, visit the associated frame (using the @code{up}, -@code{down}, or @code{frame} commands); then type @code{info catch}. -@xref{Set Catchpoints, , Setting Catchpoints}. - @end table @@ -6418,6 +6916,7 @@ the @code{list} command. You can change this using @code{set listsize}: @item set listsize @var{count} Make the @code{list} command display @var{count} source lines (unless the @code{list} argument explicitly specifies some other number). +Setting @var{count} to 0 means there's no limit. @kindex show listsize @item show listsize @@ -6493,6 +6992,11 @@ linespec. @item @var{filename}:@var{linenum} Specifies the line @var{linenum} in the source file @var{filename}. +If @var{filename} is a relative file name, then it will match any +source file name with the same trailing components. For example, if +@var{filename} is @samp{gcc/expr.c}, then it will match source file +name of @file{/build/trunk/gcc/expr.c}, but not +@file{/build/trunk/libcpp/expr.c} or @file{/build/trunk/gcc/x-expr.c}. @item @var{function} Specifies the line that begins the body of the function @var{function}. @@ -6551,6 +7055,19 @@ specify the function unambiguously, e.g., if there are several functions with identical names in different source files. @end table +@cindex breakpoint at static probe point +@item -pstap|-probe-stap @r{[}@var{objfile}:@r{[}@var{provider}:@r{]}@r{]}@var{name} +The @sc{gnu}/Linux tool @code{SystemTap} provides a way for +applications to embed static probes. @xref{Static Probe Points}, for more +information on finding and using static probes. This form of linespec +specifies the location of such a static probe. + +If @var{objfile} is given, only probes coming from that shared library +or executable matching @var{objfile} as a regular expression are considered. +If @var{provider} is given, then only probes from that provider are considered. +If several probes match the spec, @value{GDBN} will insert a breakpoint at +each one of those probes. + @end table @@ -6620,6 +7137,7 @@ regular expression. @table @code @kindex search @kindex forward-search +@kindex fo @r{(@code{forward-search})} @item forward-search @var{regexp} @itemx search @var{regexp} The command @samp{forward-search @var{regexp}} checks each line, @@ -7000,6 +7518,11 @@ Dump of assembler code from 0x400281 to 0x40028b: End of assembler dump. @end smallexample +Addresses cannot be specified as a linespec (@pxref{Specify Location}). +So, for example, if you want to disassemble function @code{bar} +in file @file{foo.c}, you must type @samp{disassemble 'foo.c'::bar} +and not @samp{disassemble foo.c:bar}. + Some architectures have more than one commonly-used set of instruction mnemonics or other syntax. @@ -7057,9 +7580,6 @@ instruction. @cindex examining data @kindex print @kindex inspect -@c "inspect" is not quite a synonym if you are using Epoch, which we do not -@c document because it is nonstandard... Under Epoch it displays in a -@c different window or something like that. The usual way to examine data in your program is with the @code{print} command (abbreviated @code{p}), or its synonym @code{inspect}. It evaluates and prints the value of an expression of the language your @@ -7093,6 +7613,153 @@ fields of a struct or a class are declared, use the @code{ptype @var{exp}} command rather than @code{print}. @xref{Symbols, ,Examining the Symbol Table}. +@cindex exploring hierarchical data structures +@kindex explore +Another way of examining values of expressions and type information is +through the Python extension command @code{explore} (available only if +the @value{GDBN} build is configured with @code{--with-python}). It +offers an interactive way to start at the highest level (or, the most +abstract level) of the data type of an expression (or, the data type +itself) and explore all the way down to leaf scalar values/fields +embedded in the higher level data types. + +@table @code +@item explore @var{arg} +@var{arg} is either an expression (in the source language), or a type +visible in the current context of the program being debugged. +@end table + +The working of the @code{explore} command can be illustrated with an +example. If a data type @code{struct ComplexStruct} is defined in your +C program as + +@smallexample +struct SimpleStruct +@{ + int i; + double d; +@}; + +struct ComplexStruct +@{ + struct SimpleStruct *ss_p; + int arr[10]; +@}; +@end smallexample + +@noindent +followed by variable declarations as + +@smallexample +struct SimpleStruct ss = @{ 10, 1.11 @}; +struct ComplexStruct cs = @{ &ss, @{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 @} @}; +@end smallexample + +@noindent +then, the value of the variable @code{cs} can be explored using the +@code{explore} command as follows. + +@smallexample +(gdb) explore cs +The value of `cs' is a struct/class of type `struct ComplexStruct' with +the following fields: + + ss_p = + arr = + +Enter the field number of choice: +@end smallexample + +@noindent +Since the fields of @code{cs} are not scalar values, you are being +prompted to chose the field you want to explore. Let's say you choose +the field @code{ss_p} by entering @code{0}. Then, since this field is a +pointer, you will be asked if it is pointing to a single value. From +the declaration of @code{cs} above, it is indeed pointing to a single +value, hence you enter @code{y}. If you enter @code{n}, then you will +be asked if it were pointing to an array of values, in which case this +field will be explored as if it were an array. + +@smallexample +`cs.ss_p' is a pointer to a value of type `struct SimpleStruct' +Continue exploring it as a pointer to a single value [y/n]: y +The value of `*(cs.ss_p)' is a struct/class of type `struct +SimpleStruct' with the following fields: + + i = 10 .. (Value of type `int') + d = 1.1100000000000001 .. (Value of type `double') + +Press enter to return to parent value: +@end smallexample + +@noindent +If the field @code{arr} of @code{cs} was chosen for exploration by +entering @code{1} earlier, then since it is as array, you will be +prompted to enter the index of the element in the array that you want +to explore. + +@smallexample +`cs.arr' is an array of `int'. +Enter the index of the element you want to explore in `cs.arr': 5 + +`(cs.arr)[5]' is a scalar value of type `int'. + +(cs.arr)[5] = 4 + +Press enter to return to parent value: +@end smallexample + +In general, at any stage of exploration, you can go deeper towards the +leaf values by responding to the prompts appropriately, or hit the +return key to return to the enclosing data structure (the @i{higher} +level data structure). + +Similar to exploring values, you can use the @code{explore} command to +explore types. Instead of specifying a value (which is typically a +variable name or an expression valid in the current context of the +program being debugged), you specify a type name. If you consider the +same example as above, your can explore the type +@code{struct ComplexStruct} by passing the argument +@code{struct ComplexStruct} to the @code{explore} command. + +@smallexample +(gdb) explore struct ComplexStruct +@end smallexample + +@noindent +By responding to the prompts appropriately in the subsequent interactive +session, you can explore the type @code{struct ComplexStruct} in a +manner similar to how the value @code{cs} was explored in the above +example. + +The @code{explore} command also has two sub-commands, +@code{explore value} and @code{explore type}. The former sub-command is +a way to explicitly specify that value exploration of the argument is +being invoked, while the latter is a way to explicitly specify that type +exploration of the argument is being invoked. + +@table @code +@item explore value @var{expr} +@cindex explore value +This sub-command of @code{explore} explores the value of the +expression @var{expr} (if @var{expr} is an expression valid in the +current context of the program being debugged). The behavior of this +command is identical to that of the behavior of the @code{explore} +command being passed the argument @var{expr}. + +@item explore type @var{arg} +@cindex explore type +This sub-command of @code{explore} explores the type of @var{arg} (if +@var{arg} is a type visible in the current context of program being +debugged), or the type of the value/expression @var{arg} (if @var{arg} +is an expression valid in the current context of the program being +debugged). If @var{arg} is a type, then the behavior of this command is +identical to that of the @code{explore} command being passed the +argument @var{arg}. If @var{arg} is an expression, then the behavior of +this command will be identical to that of the @code{explore} command +being passed the type of @var{arg} as the argument. +@end table + @menu * Expressions:: Expressions * Ambiguous Expressions:: Ambiguous Expressions @@ -7105,6 +7772,7 @@ Table}. * Pretty Printing:: Python pretty printing * Value History:: Value history * Convenience Vars:: Convenience variables +* Convenience Funs:: Convenience functions * Registers:: Registers * Floating Point Hardware:: Floating point hardware * Vector Unit:: Vector Unit @@ -7307,7 +7975,7 @@ scope is a single source file even if the current execution point is not in this file. But it is possible to have more than one such variable or function with the same name (in different source files). If that happens, referring to that name has unpredictable effects. If you wish, -you can specify a static variable in a particular function or file, +you can specify a static variable in a particular function or file by using the colon-colon (@code{::}) notation: @cindex colon-colon, context for variables/functions @@ -7330,8 +7998,49 @@ to print a global value of @code{x} defined in @file{f2.c}: (@value{GDBP}) p 'f2.c'::x @end smallexample +The @code{::} notation is normally used for referring to +static variables, since you typically disambiguate uses of local variables +in functions by selecting the appropriate frame and using the +simple name of the variable. However, you may also use this notation +to refer to local variables in frames enclosing the selected frame: + +@smallexample +void +foo (int a) +@{ + if (a < 10) + bar (a); + else + process (a); /* Stop here */ +@} + +int +bar (int a) +@{ + foo (a + 5); +@} +@end smallexample + +@noindent +For example, if there is a breakpoint at the commented line, +here is what you might see +when the program stops after executing the call @code{bar(0)}: + +@smallexample +(@value{GDBP}) p a +$1 = 10 +(@value{GDBP}) p bar::a +$2 = 5 +(@value{GDBP}) up 2 +#2 0x080483d0 in foo (a=5) at foobar.c:12 +(@value{GDBP}) p a +$3 = 5 +(@value{GDBP}) p bar::a +$4 = 0 +@end smallexample + @cindex C@t{++} scope resolution -This use of @samp{::} is very rarely in conflict with the very similar +These uses of @samp{::} are very rarely in conflict with the very similar use of the same notation in C@t{++}. @value{GDBN} also supports use of the C@t{++} scope resolution operator in @value{GDBN} expressions. @c FIXME: Um, so what happens in one of those rare cases where it's in @@ -7970,6 +8679,24 @@ does not show the symbol name and filename of the referent, even with the appropriate @code{set print} options turned on. @end quotation +You can also enable @samp{/a}-like formatting all the time using +@samp{set print symbol on}: + +@table @code +@item set print symbol on +Tell @value{GDBN} to print the symbol corresponding to an address, if +one exists. + +@item set print symbol off +Tell @value{GDBN} not to print the symbol corresponding to an +address. In this mode, @value{GDBN} will still print the symbol +corresponding to pointers to functions. This is the default. + +@item show print symbol +Show whether @value{GDBN} will display the symbol corresponding to an +address. +@end table + Other settings control how different kinds of objects are printed: @table @code @@ -8341,10 +9068,10 @@ represent C@t{++} names. The choices for @var{style} are currently: @table @code @item auto Allow @value{GDBN} to choose a decoding style by inspecting your program. +This is the default. @item gnu Decode based on the @sc{gnu} C@t{++} compiler (@code{g++}) encoding algorithm. -This is the default. @item hp Decode based on the HP ANSI C@t{++} (@code{aCC}) encoding algorithm. @@ -8373,7 +9100,8 @@ When displaying a pointer to an object, identify the @emph{actual} the virtual function table. Note that the virtual function table is required---this feature can only work for objects that have run-time type identification; a single virtual method in the object's declared -type is sufficient. +type is sufficient. Note that this setting is also taken into account when +working with variable objects via MI (@pxref{GDB/MI}). @item set print object off Display only the declared type of objects, without reference to the @@ -8711,9 +9439,10 @@ variable, when used as an expression, has the type of its current value. @table @code @kindex show convenience -@cindex show all user variables +@cindex show all user variables and functions @item show convenience -Print a list of convenience variables used so far, and their values. +Print a list of convenience variables used so far, and their values, +as well as a list of the convenience functions. Abbreviated @code{show conv}. @kindex init-if-undefined @@ -8766,6 +9495,10 @@ to match the format in which the data was printed. The variable @code{$_exitcode} is automatically set to the exit code when the program being debugged terminates. +@item $_probe_argc +@itemx $_probe_arg0@dots{}$_probe_arg11 +Arguments to a static probe. @xref{Static Probe Points}. + @item $_sdata @vindex $_sdata@r{, inspect, convenience variable} The variable @code{$_sdata} contains extra collected static tracepoint @@ -8794,6 +9527,9 @@ 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. +@node Convenience Funs +@section Convenience Functions + @cindex convenience functions @value{GDBN} also supplies some @dfn{convenience functions}. These have a syntax similar to convenience variables. A convenience @@ -8801,6 +9537,38 @@ function can be used in an expression just like an ordinary function; however, a convenience function is implemented internally to @value{GDBN}. +These functions require @value{GDBN} to be configured with +@code{Python} support. + +@table @code + +@item $_memeq(@var{buf1}, @var{buf2}, @var{length}) +@findex $_memeq@r{, convenience function} +Returns one if the @var{length} bytes at the addresses given by +@var{buf1} and @var{buf2} are equal. +Otherwise it returns zero. + +@item $_regex(@var{str}, @var{regex}) +@findex $_regex@r{, convenience function} +Returns one if the string @var{str} matches the regular expression +@var{regex}. Otherwise it returns zero. +The syntax of the regular expression is that specified by @code{Python}'s +regular expression support. + +@item $_streq(@var{str1}, @var{str2}) +@findex $_streq@r{, convenience function} +Returns one if the strings @var{str1} and @var{str2} are equal. +Otherwise it returns zero. + +@item $_strlen(@var{str}) +@findex $_strlen@r{, convenience function} +Returns the length of string @var{str}. + +@end table + +@value{GDBN} provides the ability to list and get help on +convenience functions. + @table @code @item help function @kindex help function @@ -8979,24 +9747,6 @@ layout vary depending on the hardware. @value{GDBN} provides interfaces to useful OS facilities that can help you debug your program. -@cindex @code{ptrace} system call -@cindex @code{struct user} contents -When @value{GDBN} runs on a @dfn{Posix system} (such as GNU or Unix -machines), it interfaces with the inferior via the @code{ptrace} -system call. The operating system creates a special sata structure, -called @code{struct user}, for this interface. You can use the -command @code{info udot} to display the contents of this data -structure. - -@table @code -@item info udot -@kindex info udot -Display the contents of the @code{struct user} maintained by the OS -kernel for the program being debugged. @value{GDBN} displays the -contents of @code{struct user} as a list of hex numbers, similar to -the @code{examine} command. -@end table - @cindex auxiliary vector @cindex vector, auxiliary Some operating systems supply an @dfn{auxiliary vector} to programs at @@ -9023,23 +9773,109 @@ most appropriate form for a recognized tag, and in hexadecimal for an unrecognized tag. @end table -On some targets, @value{GDBN} can access operating-system-specific information -and display it to user, without interpretation. For remote targets, -this functionality depends on the remote stub's support of the +On some targets, @value{GDBN} can access operating system-specific +information and show it to you. The types of information available +will differ depending on the type of operating system running on the +target. The mechanism used to fetch the data is described in +@ref{Operating System Information}. For remote targets, this +functionality depends on the remote stub's support of the @samp{qXfer:osdata:read} packet, see @ref{qXfer osdata read}. @table @code @kindex info os -@item info os -List the types of OS information available for the target. If the -target does not return a list of possible types, this command will -report an error. +@item info os @var{infotype} + +Display OS information of the requested type. +On @sc{gnu}/Linux, the following values of @var{infotype} are valid: + +@anchor{linux info os infotypes} +@table @code @kindex info os processes -@item info os processes +@item processes Display the list of processes on the target. For each process, -@value{GDBN} prints the process identifier, the name of the user, and -the command corresponding to the process. +@value{GDBN} prints the process identifier, the name of the user, the +command corresponding to the process, and the list of processor cores +that the process is currently running on. (To understand what these +properties mean, for this and the following info types, please consult +the general @sc{gnu}/Linux documentation.) + +@kindex info os procgroups +@item procgroups +Display the list of process groups on the target. For each process, +@value{GDBN} prints the identifier of the process group that it belongs +to, the command corresponding to the process group leader, the process +identifier, and the command line of the process. The list is sorted +first by the process group identifier, then by the process identifier, +so that processes belonging to the same process group are grouped together +and the process group leader is listed first. + +@kindex info os threads +@item threads +Display the list of threads running on the target. For each thread, +@value{GDBN} prints the identifier of the process that the thread +belongs to, the command of the process, the thread identifier, and the +processor core that it is currently running on. The main thread of a +process is not listed. + +@kindex info os files +@item files +Display the list of open file descriptors on the target. For each +file descriptor, @value{GDBN} prints the identifier of the process +owning the descriptor, the command of the owning process, the value +of the descriptor, and the target of the descriptor. + +@kindex info os sockets +@item sockets +Display the list of Internet-domain sockets on the target. For each +socket, @value{GDBN} prints the address and port of the local and +remote endpoints, the current state of the connection, the creator of +the socket, the IP address family of the socket, and the type of the +connection. + +@kindex info os shm +@item shm +Display the list of all System V shared-memory regions on the target. +For each shared-memory region, @value{GDBN} prints the region key, +the shared-memory identifier, the access permissions, the size of the +region, the process that created the region, the process that last +attached to or detached from the region, the current number of live +attaches to the region, and the times at which the region was last +attached to, detach from, and changed. + +@kindex info os semaphores +@item semaphores +Display the list of all System V semaphore sets on the target. For each +semaphore set, @value{GDBN} prints the semaphore set key, the semaphore +set identifier, the access permissions, the number of semaphores in the +set, the user and group of the owner and creator of the semaphore set, +and the times at which the semaphore set was operated upon and changed. + +@kindex info os msg +@item msg +Display the list of all System V message queues on the target. For each +message queue, @value{GDBN} prints the message queue key, the message +queue identifier, the access permissions, the current number of bytes +on the queue, the current number of messages on the queue, the processes +that last sent and received a message on the queue, the user and group +of the owner and creator of the message queue, the times at which a +message was last sent and received on the queue, and the time at which +the message queue was last changed. + +@kindex info os modules +@item modules +Display the list of all loaded kernel modules on the target. For each +module, @value{GDBN} prints the module name, the size of the module in +bytes, the number of times the module is used, the dependencies of the +module, the status of the module, and the address of the loaded module +in memory. +@end table + +@item info os +If @var{infotype} is omitted, then list the possible values for +@var{infotype} and the kind of OS information available for each +@var{infotype}. If the target does not return a list of possible +types, this command will report an error. @end table @node Memory Region Attributes @@ -9299,7 +10135,7 @@ specified, the file name defaults to @file{core.@var{pid}}, where @var{pid} is the inferior process ID. Note that this command is implemented only for some systems (as of -this writing, @sc{gnu}/Linux, FreeBSD, Solaris, Unixware, and S390). +this writing, @sc{gnu}/Linux, FreeBSD, Solaris, and S390). @end table @node Character Sets @@ -9770,14 +10606,6 @@ 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} @@ -10718,6 +11546,16 @@ Collect all local variables. Collect the return address. This is helpful if you want to see more of a backtrace. +@item $_probe_argc +Collects the number of arguments from the static probe at which the +tracepoint is located. +@xref{Static Probe Points}. + +@item $_probe_arg@var{n} +@var{n} is an integer between 0 and 11. Collects the @var{n}th argument +from the static probe at which the tracepoint is located. +@xref{Static Probe Points}. + @item $_sdata @vindex $_sdata@r{, collect} Collect static tracepoint marker specific data. Only available for @@ -10822,6 +11660,9 @@ tracing: @itemize @bullet @item its passcount as given by the @code{passcount @var{n}} command + +@item +the state about installed on target of each location @end itemize @smallexample @@ -10834,6 +11675,15 @@ Num Type Disp Enb Address What collect globfoo2 end pass count 1200 +2 tracepoint keep y + collect $eip +2.1 y 0x0804859c in func4 at change-loc.h:35 + installed on target +2.2 y 0xb7ffc480 in func4 at change-loc.h:35 + installed on target +2.3 y set_tracepoint +3 tracepoint keep y 0x080485b1 in foo at change-loc.c:29 + not installed on target (@value{GDBP}) @end smallexample @@ -11023,6 +11873,25 @@ for instance if you are looking at frames from a trace file. @end table +@table @code +@item set trace-buffer-size @var{n} +@kindex set trace-buffer-size +Request that the target use a trace buffer of @var{n} bytes. Not all +targets will honor the request; they may have a compiled-in size for +the trace buffer, or some other limitation. Set to a value of +@code{-1} to let the target use whatever size it likes. This is also +the default. + +@item show trace-buffer-size +@kindex show trace-buffer-size +Show the current requested size for the trace buffer. Note that this +will only match the actual size if the target supports size-setting, +and was able to handle the requested size. For instance, if the +target can only change buffer size between runs, this variable will +not reflect the change until the next run starts. Use @code{tstatus} +to get a report of the actual buffer size. +@end table + @table @code @item set trace-user @var{text} @kindex set trace-user @@ -12028,29 +12897,18 @@ List all the filename extensions and the associated languages. @node Checks @section Type and Range Checking -@quotation -@emph{Warning:} In this release, the @value{GDBN} commands for type and range -checking are included, but they do not yet have any effect. This -section documents the intended facilities. -@end quotation -@c FIXME remove warning when type/range code added - Some languages are designed to guard you against making seemingly common errors through a series of compile- and run-time checks. These include -checking the type of arguments to functions and operators, and making +checking the type of arguments to functions and operators and making sure mathematical overflows are caught at run time. Checks such as these help to ensure a program's correctness once it has been compiled -by eliminating type mismatches, and providing active checks for range +by eliminating type mismatches and providing active checks for range errors when your program is running. -@value{GDBN} can check for conditions like the above if you wish. -Although @value{GDBN} does not check the statements in your program, -it can check expressions entered directly into @value{GDBN} for -evaluation via the @code{print} command, for example. As with the -working language, @value{GDBN} can also decide whether or not to check -automatically based on your program's source language. -@xref{Supported Languages, ,Supported Languages}, for the default -settings of supported languages. +By default @value{GDBN} checks for these errors according to the +rules of the current source language. Although @value{GDBN} does not check +the statements in your program, it can check expressions entered directly +into @value{GDBN} for evaluation via the @code{print} command, for example. @menu * Type Checking:: An overview of type checking @@ -12062,69 +12920,51 @@ settings of supported languages. @node Type Checking @subsection An Overview of Type Checking -Some languages, such as Modula-2, are strongly typed, meaning that the +Some languages, such as C and C@t{++}, are strongly typed, meaning that the arguments to operators and functions have to be of the correct type, otherwise an error occurs. These checks prevent type mismatch errors from ever causing any run-time problems. For example, @smallexample -1 + 2 @result{} 3 +int klass::my_method(char *b) @{ return b ? 1 : 2; @} + +(@value{GDBP}) print obj.my_method (0) +$1 = 2 @exdent but -@error{} 1 + 2.3 +(@value{GDBP}) print obj.my_method (0x1234) +Cannot resolve method klass::my_method to any overloaded instance @end smallexample -The second example fails because the @code{CARDINAL} 1 is not -type-compatible with the @code{REAL} 2.3. +The second example fails because in C@t{++} the integer constant +@samp{0x1234} is not type-compatible with the pointer parameter type. -For the expressions you use in @value{GDBN} commands, you can tell the -@value{GDBN} type checker to skip checking; +For the expressions you use in @value{GDBN} commands, you can tell +@value{GDBN} to not enforce strict type checking or to treat any mismatches as errors and abandon the expression; -or to only issue warnings when type mismatches occur, -but evaluate the expression anyway. When you choose the last of -these, @value{GDBN} evaluates expressions like the second example above, but -also issues a warning. +When type checking is disabled, @value{GDBN} successfully evaluates +expressions like the second example above. -Even if you turn type checking off, there may be other reasons +Even if type checking is off, there may be other reasons related to type that prevent @value{GDBN} from evaluating an expression. For instance, @value{GDBN} does not know how to add an @code{int} and a @code{struct foo}. These particular type errors have nothing to do -with the language in use, and usually arise from expressions, such as -the one described above, which make little sense to evaluate anyway. - -Each language defines to what degree it is strict about type. For -instance, both Modula-2 and C require the arguments to arithmetical -operators to be numbers. In C, enumerated types and pointers can be -represented as numbers, so that they are valid arguments to mathematical -operators. @xref{Supported Languages, ,Supported Languages}, for further -details on specific languages. +with the language in use and usually arise from expressions which make +little sense to evaluate anyway. -@value{GDBN} provides some additional commands for controlling the type checker: +@value{GDBN} provides some additional commands for controlling type checking: @kindex set check type @kindex show check type @table @code -@item set check type auto -Set type checking on or off based on the current working language. -@xref{Supported Languages, ,Supported Languages}, for the default settings for -each language. - @item set check type on @itemx set check type off -Set type checking on or off, overriding the default setting for the -current working language. Issue a warning if the setting does not -match the language default. If any type mismatches occur in +Set strict type checking on or off. If any type mismatches occur in evaluating an expression while type checking is on, @value{GDBN} prints a message and aborts evaluation of the expression. -@item set check type warn -Cause the type checker to issue warnings, but to always attempt to -evaluate the expression. Evaluating the expression may still -be impossible for other reasons. For example, @value{GDBN} cannot add -numbers and structures. - -@item show type -Show the current setting of the type checker, and whether or not @value{GDBN} -is setting it automatically. +@item show check type +Show the current setting of type checking and whether @value{GDBN} +is enforcing strict type checking rules. @end table @cindex range checking @@ -12190,8 +13030,8 @@ being set automatically by @value{GDBN}. @node Supported Languages @section Supported Languages -@value{GDBN} supports C, C@t{++}, D, Objective-C, Fortran, Java, OpenCL C, Pascal, -assembly, Modula-2, and Ada. +@value{GDBN} supports C, C@t{++}, D, Go, Objective-C, Fortran, Java, +OpenCL C, Pascal, assembly, Modula-2, and Ada. @c This is false ... Some @value{GDBN} features may be used in expressions regardless of the language you use: the @value{GDBN} @code{@@} and @code{::} operators, @@ -12210,6 +13050,7 @@ language reference or tutorial. @menu * C:: C and C@t{++} * D:: D +* Go:: Go * Objective-C:: Objective-C * OpenCL C:: OpenCL C * Fortran:: Fortran @@ -12574,8 +13415,8 @@ specification. @cindex C and C@t{++} defaults -If you allow @value{GDBN} to set type and range checking automatically, they -both default to @code{off} whenever the working language changes to +If you allow @value{GDBN} to set range checking automatically, it +defaults to @code{off} whenever the working language changes to C or C@t{++}. This happens regardless of whether you or @value{GDBN} selects the working language. @@ -12586,37 +13427,15 @@ these files, it sets the working language to C or C@t{++}. @xref{Automatically, ,Having @value{GDBN} Infer the Source Language}, for further details. -@c Type checking is (a) primarily motivated by Modula-2, and (b) -@c unimplemented. If (b) changes, it might make sense to let this node -@c appear even if Mod-2 does not, but meanwhile ignore it. roland 16jul93. - @node C Checks @subsubsection C and C@t{++} Type and Range Checks @cindex C and C@t{++} checks -By default, when @value{GDBN} parses C or C@t{++} expressions, type checking -is not used. However, if you turn type checking on, @value{GDBN} -considers two variables type equivalent if: - -@itemize @bullet -@item -The two variables are structured and have the same structure, union, or -enumerated tag. - -@item -The two variables have the same type name, or types that have been -declared equivalent through @code{typedef}. - -@ignore -@c leaving this out because neither J Gilmore nor R Pesch understand it. -@c FIXME--beers? -@item -The two @code{struct}, @code{union}, or @code{enum} variables are -declared in the same declaration. (Note: this may not be true for all C -compilers.) -@end ignore -@end itemize +By default, when @value{GDBN} parses C or C@t{++} expressions, strict type +checking is used. However, if you turn type checking off, @value{GDBN} +will allow certain non-standard conversions, such as promoting integer +constants to pointers. Range checking, if turned on, is done on mathematical operations. Array indices are not checked, since they are often used to index a pointer @@ -12669,6 +13488,12 @@ Print inheritance relationships as well as other information for type @var{typename}. @xref{Symbols, ,Examining the Symbol Table}. +@item info vtbl @var{expression}. +The @code{info vtbl} command can be used to display the virtual +method tables of the object computed by @var{expression}. This shows +one entry per virtual table; there may be multiple virtual tables when +multiple inheritance is in use. + @cindex C@t{++} symbol display @item set print demangle @itemx show print demangle @@ -12756,6 +13581,55 @@ See @ref{PowerPC,,PowerPC} for more details. GDC, LDC or DMD compilers. Currently @value{GDBN} supports only one D specific feature --- dynamic arrays. +@node Go +@subsection Go + +@cindex Go (programming language) +@value{GDBN} can be used to debug programs written in Go and compiled with +@file{gccgo} or @file{6g} compilers. + +Here is a summary of the Go-specific features and restrictions: + +@table @code +@cindex current Go package +@item The current Go package +The name of the current package does not need to be specified when +specifying global variables and functions. + +For example, given the program: + +@example +package main +var myglob = "Shall we?" +func main () @{ + // ... +@} +@end example + +When stopped inside @code{main} either of these work: + +@example +(gdb) p myglob +(gdb) p main.myglob +@end example + +@cindex builtin Go types +@item Builtin Go types +The @code{string} type is recognized by @value{GDBN} and is printed +as a string. + +@cindex builtin Go functions +@item Builtin Go functions +The @value{GDBN} expression parser recognizes the @code{unsafe.Sizeof} +function and handles it internally. + +@cindex restrictions on Go expressions +@item Restrictions on Go expressions +All Go operators are supported except @code{&^}. +The Go @code{_} ``blank identifier'' is not supported. +Automatic dereferencing of pointers is not supported. +@end table + @node Objective-C @subsection Objective-C @@ -14331,6 +15205,42 @@ case-insensitive matches. This command shows the current setting of case sensitivity for symbols lookups. +@kindex set print type methods +@item set print type methods +@itemx set print type methods on +@itemx set print type methods off +Normally, when @value{GDBN} prints a class, it displays any methods +declared in that class. You can control this behavior either by +passing the appropriate flag to @code{ptype}, or using @command{set +print type methods}. Specifying @code{on} will cause @value{GDBN} to +display the methods; this is the default. Specifying @code{off} will +cause @value{GDBN} to omit the methods. + +@kindex show print type methods +@item show print type methods +This command shows the current setting of method display when printing +classes. + +@kindex set print type typedefs +@item set print type typedefs +@itemx set print type typedefs on +@itemx set print type typedefs off + +Normally, when @value{GDBN} prints a class, it displays any typedefs +defined in that class. You can control this behavior either by +passing the appropriate flag to @code{ptype}, or using @command{set +print type typedefs}. Specifying @code{on} will cause @value{GDBN} to +display the typedef definitions; this is the default. Specifying +@code{off} will cause @value{GDBN} to omit the typedef definitions. +Note that this controls whether the typedef definition itself is +printed, not whether typedef names are substituted when printing other +types. + +@kindex show print type typedefs +@item show print type typedefs +This command shows the current setting of typedef display when +printing classes. + @kindex info address @cindex address of a symbol @item info address @var{symbol} @@ -14371,7 +15281,7 @@ __read_nocancel + 6 in section .text of /usr/lib64/libc.so.6 @end smallexample @kindex whatis -@item whatis [@var{arg}] +@item whatis[/@var{flags}] [@var{arg}] Print the data type of @var{arg}, which can be either an expression or a name of a data type. With no argument, print the data type of @code{$}, the last value in the value history. @@ -14401,8 +15311,34 @@ For C code, the type names may also have the form @samp{class @var{class-name}}, @samp{struct @var{struct-tag}}, @samp{union @var{union-tag}} or @samp{enum @var{enum-tag}}. +@var{flags} can be used to modify how the type is displayed. +Available flags are: + +@table @code +@item r +Display in ``raw'' form. Normally, @value{GDBN} substitutes template +parameters and typedefs defined in a class when printing the class' +members. The @code{/r} flag disables this. + +@item m +Do not print methods defined in the class. + +@item M +Print methods defined in the class. This is the default, but the flag +exists in case you change the default with @command{set print type methods}. + +@item t +Do not print typedefs defined in the class. Note that this controls +whether the typedef definition itself is printed, not whether typedef +names are substituted when printing other types. + +@item T +Print typedefs defined in the class. This is the default, but the flag +exists in case you change the default with @command{set print type typedefs}. +@end table + @kindex ptype -@item ptype [@var{arg}] +@item ptype[/@var{flags}] [@var{arg}] @code{ptype} accepts the same arguments as @code{whatis}, but prints a detailed description of the type, instead of just the name of the type. @xref{Expressions, ,Expressions}. @@ -14497,6 +15433,22 @@ This command differs from @code{ptype} in two ways: first, like @code{whatis}, it does not print a detailed description; second, it lists all source files where a type is defined. +@kindex info type-printers +@item info type-printers +Versions of @value{GDBN} that ship with Python scripting enabled may +have ``type printers'' available. When using @command{ptype} or +@command{whatis}, these printers are consulted when the name of a type +is needed. @xref{Type Printing API}, for more information on writing +type printers. + +@code{info type-printers} displays all the available type printers. + +@kindex enable type-printer +@kindex disable type-printer +@item enable type-printer @var{name}@dots{} +@item disable type-printer @var{name}@dots{} +These commands can be used to enable or disable type printers. + @kindex info scope @cindex local variables @item info scope @var{location} @@ -14603,33 +15555,6 @@ from the @code{ptype} command can be overwhelming and hard to use. The which match the regular-expression @var{regexp}. @end ignore -@cindex reloading symbols -Some systems allow individual object files that make up your program to -be replaced without stopping and restarting your program. For example, -in VxWorks you can simply recompile a defective object file and keep on -running. If you are running on one of these systems, you can allow -@value{GDBN} to reload the symbols for automatically relinked modules: - -@table @code -@kindex set symbol-reloading -@item set symbol-reloading on -Replace symbol definitions for the corresponding source file when an -object file with a particular name is seen again. - -@item set symbol-reloading off -Do not replace symbol definitions when encountering object files of the -same name more than once. This is the default state; if you are not -running on a system that permits automatic relinking of modules, you -should leave @code{symbol-reloading} off, since otherwise @value{GDBN} -may discard symbols when linking large programs, that may contain -several modules (from different directories or libraries) with the same -name. - -@kindex show symbol-reloading -@item show symbol-reloading -Show the current @code{on} or @code{off} setting. -@end table - @cindex opaque data types @kindex set opaque-type-resolution @item set opaque-type-resolution on @@ -14873,8 +15798,11 @@ an address of your own choosing, with the following commands: @table @code @kindex jump +@kindex j @r{(@code{jump})} @item jump @var{linespec} +@itemx j @var{linespec} @itemx jump @var{location} +@itemx j @var{location} Resume execution at line @var{linespec} or at address given by @var{location}. Execution stops again immediately if there is a breakpoint there. @xref{Specify Location}, for a description of the @@ -14929,7 +15857,7 @@ SIGINT} are both ways of sending an interrupt signal. Alternatively, if @var{signal} is zero, continue execution without giving a signal. This is useful when your program stopped on account of -a signal and would ordinary see the signal when resumed with the +a signal and would ordinarily see the signal when resumed with the @code{continue} command; @samp{signal 0} causes it to resume without a signal. @@ -15152,6 +16080,7 @@ program. To debug a core dump of a previous run, you must also tell @menu * Files:: Commands to specify files * Separate Debug Files:: Debugging information in separate files +* MiniDebugInfo:: Debugging information in a special section * Index Files:: Index files speed up GDB * Symbol Errors:: Errors reading symbol files * Data Files:: GDB data files @@ -15553,8 +16482,14 @@ discarded. @end table Sometimes you may wish that @value{GDBN} stops and gives you control -when any of shared library events happen. Use the @code{set -stop-on-solib-events} command for this: +when any of shared library events happen. The best way to do this is +to use @code{catch load} and @code{catch unload} (@pxref{Set +Catchpoints}). + +@value{GDBN} also supports the the @code{set stop-on-solib-events} +command for this. This command exists for historical reasons. It is +less useful than setting a catchpoint, because it does not allow for +conditions or commands as a catchpoint does. @table @code @item set stop-on-solib-events @@ -15778,7 +16713,7 @@ Show whether a source file may have multiple base names. @cindex debugging information in separate files @cindex @file{.debug} subdirectories @cindex debugging information directory, global -@cindex global debugging information directory +@cindex global debugging information directories @cindex build ID, and separate debugging files @cindex @file{.build-id} directory @@ -15823,14 +16758,14 @@ uses two different methods of looking for the debug file: @item For the ``debug link'' method, @value{GDBN} looks up the named file in the directory of the executable file, then in a subdirectory of that -directory named @file{.debug}, and finally under the global debug -directory, in a subdirectory whose name is identical to the leading +directory named @file{.debug}, and finally under each one of the global debug +directories, in a subdirectory whose name is identical to the leading directories of the executable's absolute file name. @item For the ``build ID'' method, @value{GDBN} looks in the -@file{.build-id} subdirectory of the global debug directory for a file -named @file{@var{nn}/@var{nnnnnnnn}.debug}, where @var{nn} are the +@file{.build-id} subdirectory of each one of the global debug directories for +a file named @file{@var{nn}/@var{nnnnnnnn}.debug}, where @var{nn} are the first 2 hex characters of the build ID bit string, and @var{nnnnnnnn} are the rest of the bit string. (Real build ID strings are 32 or more hex characters, not 10.) @@ -15839,7 +16774,7 @@ hex characters, not 10.) So, for example, suppose you ask @value{GDBN} to debug @file{/usr/bin/ls}, which has a debug link that specifies the file @file{ls.debug}, and a build ID whose value in hex is -@code{abcdef1234}. If the global debug directory is +@code{abcdef1234}. If the list of the global debug directories includes @file{/usr/lib/debug}, then @value{GDBN} will look for the following debug information files, in the indicated order: @@ -15854,16 +16789,19 @@ debug information files, in the indicated order: @file{/usr/lib/debug/usr/bin/ls.debug}. @end itemize -You can set the global debugging info directory's name, and view the -name @value{GDBN} is currently using. +@anchor{debug-file-directory} +Global debugging info directories default to what is set by @value{GDBN} +configure option @option{--with-separate-debug-dir}. During @value{GDBN} run +you can also set the global debugging info directories, and view the list +@value{GDBN} is currently using. @table @code @kindex set debug-file-directory @item set debug-file-directory @var{directories} Set the directories which @value{GDBN} searches for separate debugging -information files to @var{directory}. Multiple directory components can be set -concatenating them by a directory separator. +information files to @var{directory}. Multiple path components can be set +concatenating them by a path separator. @kindex show debug-file-directory @item show debug-file-directory @@ -16068,6 +17006,55 @@ gnu_debuglink_crc32 (unsigned long crc, @noindent This computation does not apply to the ``build ID'' method. +@node MiniDebugInfo +@section Debugging information in a special section +@cindex separate debug sections +@cindex @samp{.gnu_debugdata} section + +Some systems ship pre-built executables and libraries that have a +special @samp{.gnu_debugdata} section. This feature is called +@dfn{MiniDebugInfo}. This section holds an LZMA-compressed object and +is used to supply extra symbols for backtraces. + +The intent of this section is to provide extra minimal debugging +information for use in simple backtraces. It is not intended to be a +replacement for full separate debugging information (@pxref{Separate +Debug Files}). The example below shows the intended use; however, +@value{GDBN} does not currently put restrictions on what sort of +debugging information might be included in the section. + +@value{GDBN} has support for this extension. If the section exists, +then it is used provided that no other source of debugging information +can be found, and that @value{GDBN} was configured with LZMA support. + +This section can be easily created using @command{objcopy} and other +standard utilities: + +@smallexample +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table +nm -D @var{binary} --format=posix --defined-only \ + | awk '@{ print $1 @}' | sort > dynsyms + +# Extract all the text (i.e. function) symbols from the debuginfo . +nm @var{binary} --format=posix --defined-only \ + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ + | sort > funcsyms + +# Keep all the function symbols not already in the dynamic symbol +# table. +comm -13 dynsyms funcsyms > keep_symbols + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +objcopy -S --remove-section .gdb_index --remove-section .comment \ + --keep-symbols=keep_symbols @var{binary} mini_debuginfo + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +xz mini_debuginfo +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} +@end smallexample @node Index Files @section Index Files Speed Up @value{GDBN} @@ -16104,6 +17091,28 @@ $ objcopy --add-section .gdb_index=symfile.gdb-index \ --set-section-flags .gdb_index=readonly symfile symfile @end smallexample +@value{GDBN} will normally ignore older versions of @file{.gdb_index} +sections that have been deprecated. Usually they are deprecated because +they are missing a new feature or have performance issues. +To tell @value{GDBN} to use a deprecated index section anyway +specify @code{set use-deprecated-index-sections on}. +The default is @code{off}. +This can speed up startup, but may result in some functionality being lost. +@xref{Index Section Format}. + +@emph{Warning:} Setting @code{use-deprecated-index-sections} to @code{on} +must be done before gdb reads the file. The following will not work: + +@smallexample +$ gdb -ex "set use-deprecated-index-sections on" +@end smallexample + +Instead you must do, for example, + +@smallexample +$ gdb -iex "set use-deprecated-index-sections on" +@end smallexample + There are currently some limitation on indices. They only work when for DWARF debugging information, not stabs. And, they do not currently work for programs using Ada. @@ -16347,7 +17356,7 @@ you must know the actual BFD name. Use the @code{show gnutarget} command to display what file format @code{gnutarget} is set to read. If you have not set @code{gnutarget}, @value{GDBN} will determine the file format for each file automatically, -and @code{show gnutarget} displays @samp{The current BDF target is "auto"}. +and @code{show gnutarget} displays @samp{The current BFD target is "auto"}. @end table @cindex common targets @@ -16479,7 +17488,7 @@ load programs into flash memory. @cindex choosing target byte order @cindex target byte order -Some types of processors, such as the MIPS, PowerPC, and Renesas SH, +Some types of processors, such as the @acronym{MIPS}, PowerPC, and Renesas SH, offer the ability to run either big-endian or little-endian byte orders. Usually the executable or symbol will include a bit to designate the endian-ness, and you will not need to worry about @@ -16764,8 +17773,10 @@ syntax is: target> gdbserver @var{comm} @var{program} [ @var{args} @dots{} ] @end smallexample -@var{comm} is either a device name (to use a serial line) or a TCP -hostname and portnumber. For example, to debug Emacs with the argument +@var{comm} is either a device name (to use a serial line), or a TCP +hostname and portnumber, or @code{-} or @code{stdio} to use +stdin/stdout of @code{gdbserver}. +For example, to debug Emacs with the argument @samp{foo.txt} and communicate with @value{GDBN} over the serial port @file{/dev/com1}: @@ -16794,6 +17805,23 @@ conflicts with another service, @code{gdbserver} prints an error message and exits.} You must use the same port number with the host @value{GDBN} @code{target remote} command. +The @code{stdio} connection is useful when starting @code{gdbserver} +with ssh: + +@smallexample +(gdb) target remote | ssh -T hostname gdbserver - hello +@end smallexample + +The @samp{-T} option to ssh is provided because we don't need a remote pty, +and we don't want escape-character handling. Ssh does this by default when +a command is provided, the flag is provided to make it explicit. +You could elide it if you want to. + +Programs started with stdio-connected gdbserver have @file{/dev/null} for +@code{stdin}, and @code{stdout},@code{stderr} are sent back to gdb for +display through a pipe connected to gdbserver. +Both @code{stdout} and @code{stderr} use the same pipe. + @subsubsection Attaching to a Running Program @cindex attach to a program, @code{gdbserver} @cindex @option{--attach}, @code{gdbserver} option @@ -17371,6 +18399,10 @@ are: @tab @code{QPassSignals} @tab @code{handle @var{signal}} +@item @code{program-signals} +@tab @code{QProgramSignals} +@tab @code{handle @var{signal}} + @item @code{hostio-close-packet} @tab @code{vFile:close} @tab @code{remote get}, @code{remote put} @@ -17391,6 +18423,10 @@ are: @tab @code{vFile:unlink} @tab @code{remote delete} +@item @code{hostio-readlink-packet} +@tab @code{vFile:readlink} +@tab Host I/O + @item @code{noack-packet} @tab @code{QStartNoAckMode} @tab Packet acknowledgment @@ -17403,6 +18439,10 @@ are: @tab @code{qAttached} @tab Querying remote process attach state. +@item @code{trace-buffer-size} +@tab @code{QTBuffer:size} +@tab @code{set trace-buffer-size} + @item @code{traceframe-info} @tab @code{qXfer:traceframe-info:read} @tab Traceframe info @@ -17414,6 +18454,10 @@ are: @item @code{disable-randomization} @tab @code{QDisableRandomization} @tab @code{set disable-randomization} + +@item @code{conditional-breakpoints-packet} +@tab @code{Z0 and Z1} +@tab @code{Support for target-side breakpoint condition evaluation} @end multitable @node Remote Stub @@ -17534,8 +18578,8 @@ subroutines: @findex set_debug_traps @cindex remote serial stub, initialization This routine arranges for @code{handle_exception} to run when your -program stops. You must call this subroutine explicitly near the -beginning of your program. +program stops. You must call this subroutine explicitly in your +program's startup code. @item handle_exception @findex handle_exception @@ -17681,13 +18725,22 @@ Make sure you have defined the supporting low-level routines @end display @item -Insert these lines near the top of your program: +Insert these lines in your program's startup code, before the main +procedure is called: @smallexample set_debug_traps(); breakpoint(); @end smallexample +On some machines, when a breakpoint trap is raised, the hardware +automatically makes the PC point to the instruction after the +breakpoint. If your machine doesn't do that, you may need to adjust +@code{handle_exception} to arrange for it to return to the instruction +after the breakpoint on this first invocation, so that your program +doesn't keep hitting the initial breakpoint instead of making +progress. + @item For the 680x0 stub only, you need to provide a variable called @code{exceptionHook}. Normally you just use: @@ -17756,7 +18809,6 @@ configurations. * DJGPP Native:: Features specific to the DJGPP port * Cygwin Native:: Features specific to the Cygwin port * Hurd Native:: Features specific to @sc{gnu} Hurd -* Neutrino:: Features specific to QNX Neutrino * Darwin:: Features specific to Darwin @end menu @@ -17816,13 +18868,17 @@ modern FreeBSD systems. Many versions of SVR4 and compatible systems provide a facility called @samp{/proc} that can be used to examine the image of a running -process using file-system subroutines. If @value{GDBN} is configured -for an operating system with this facility, the command @code{info -proc} is available to report information about the process running -your program, or about any process running on your system. @code{info -proc} works only on SVR4 systems that include the @code{procfs} code. -This includes, as of this writing, @sc{gnu}/Linux, OSF/1 (Digital -Unix), Solaris, Irix, and Unixware, but not HP-UX, for example. +process using file-system subroutines. + +If @value{GDBN} is configured for an operating system with this +facility, the command @code{info proc} is available to report +information about the process running your program, or about any +process running on your system. This includes, as of this writing, +@sc{gnu}/Linux, OSF/1 (Digital Unix), Solaris, and Irix, but +not HP-UX, for example. + +This command may also work on core files that were created on a system +that has the @samp{/proc} facility. @table @code @kindex info proc @@ -17843,6 +18899,21 @@ a thread from the process being debugged (the leading @samp{/} still needs to be present, or else @value{GDBN} will interpret the number as a process ID rather than a thread ID). +@item info proc cmdline +@cindex info proc cmdline +Show the original command line of the process. This command is +specific to @sc{gnu}/Linux. + +@item info proc cwd +@cindex info proc cwd +Show the current working directory of the process. This command is +specific to @sc{gnu}/Linux. + +@item info proc exe +@cindex info proc exe +Show the name of executable of the process. This command is specific +to @sc{gnu}/Linux. + @item info proc mappings @cindex memory address space mappings Report the memory address space ranges accessible in the program, with @@ -18535,25 +19606,6 @@ threads; you can then change the properties of individual threads with the non-default commands. @end table - -@node Neutrino -@subsection QNX Neutrino -@cindex QNX Neutrino - -@value{GDBN} provides the following commands specific to the QNX -Neutrino target: - -@table @code -@item set debug nto-debug -@kindex set debug nto-debug -When set to on, enables debugging messages specific to the QNX -Neutrino support. - -@item show debug nto-debug -@kindex show debug nto-debug -Show the current state of QNX Neutrino messages. -@end table - @node Darwin @subsection Darwin @cindex Darwin @@ -18799,8 +19851,8 @@ acceptable commands. * MicroBlaze:: Xilinx MicroBlaze * MIPS Embedded:: MIPS Embedded * OpenRISC 1000:: OpenRisc 1000 -* PA:: HP PA Embedded * PowerPC Embedded:: PowerPC Embedded +* PA:: HP PA Embedded * Sparclet:: Tsqware Sparclet * Sparclite:: Fujitsu Sparclite * Z8000:: Zilog Z8000 @@ -19106,12 +20158,12 @@ Show MicroBlaze-specific debugging level. @end table @node MIPS Embedded -@subsection MIPS Embedded +@subsection @acronym{MIPS} Embedded -@cindex MIPS boards -@value{GDBN} can use the MIPS remote debugging protocol to talk to a -MIPS board attached to a serial line. This is available when -you configure @value{GDBN} with @samp{--target=mips-idt-ecoff}. +@cindex @acronym{MIPS} boards +@value{GDBN} can use the @acronym{MIPS} remote debugging protocol to talk to a +@acronym{MIPS} board attached to a serial line. This is available when +you configure @value{GDBN} with @samp{--target=mips-elf}. @need 1000 Use these @value{GDBN} commands to specify the connection to your target board: @@ -19168,7 +20220,7 @@ Array Tech LSI33K RAID controller board. @noindent -@value{GDBN} also supports these special commands for MIPS targets: +@value{GDBN} also supports these special commands for @acronym{MIPS} targets: @table @code @item set mipsfpu double @@ -19178,9 +20230,9 @@ Array Tech LSI33K RAID controller board. @itemx show mipsfpu @kindex set mipsfpu @kindex show mipsfpu -@cindex MIPS remote floating point -@cindex floating point, MIPS remote -If your target board does not support the MIPS floating point +@cindex @acronym{MIPS} remote floating point +@cindex floating point, @acronym{MIPS} remote +If your target board does not support the @acronym{MIPS} floating point coprocessor, you should use the command @samp{set mipsfpu none} (if you need this, you may wish to put the command in your @value{GDBN} init file). This tells @value{GDBN} how to find the return value of @@ -19203,20 +20255,20 @@ As usual, you can inquire about the @code{mipsfpu} variable with @itemx set retransmit-timeout @var{seconds} @itemx show timeout @itemx show retransmit-timeout -@cindex @code{timeout}, MIPS protocol -@cindex @code{retransmit-timeout}, MIPS protocol +@cindex @code{timeout}, @acronym{MIPS} protocol +@cindex @code{retransmit-timeout}, @acronym{MIPS} protocol @kindex set timeout @kindex show timeout @kindex set retransmit-timeout @kindex show retransmit-timeout -You can control the timeout used while waiting for a packet, in the MIPS +You can control the timeout used while waiting for a packet, in the @acronym{MIPS} remote protocol, with the @code{set timeout @var{seconds}} command. The default is 5 seconds. Similarly, you can control the timeout used while waiting for an acknowledgment of a packet with the @code{set retransmit-timeout @var{seconds}} command. The default is 3 seconds. You can inspect both values with @code{show timeout} and @code{show retransmit-timeout}. (These commands are @emph{only} available when -@value{GDBN} is configured for @samp{--target=mips-idt-ecoff}.) +@value{GDBN} is configured for @samp{--target=mips-elf}.) The timeout set by @code{set timeout} does not apply when @value{GDBN} is waiting for your program to stop. In that case, @value{GDBN} waits @@ -19224,19 +20276,19 @@ forever because it has no way of knowing how long the program is going to run before stopping. @item set syn-garbage-limit @var{num} -@kindex set syn-garbage-limit@r{, MIPS remote} -@cindex synchronize with remote MIPS target +@kindex set syn-garbage-limit@r{, @acronym{MIPS} remote} +@cindex synchronize with remote @acronym{MIPS} target Limit the maximum number of characters @value{GDBN} should ignore when it tries to synchronize with the remote target. The default is 10 characters. Setting the limit to -1 means there's no limit. @item show syn-garbage-limit -@kindex show syn-garbage-limit@r{, MIPS remote} +@kindex show syn-garbage-limit@r{, @acronym{MIPS} remote} Show the current limit on the number of characters to ignore when trying to synchronize with the remote system. @item set monitor-prompt @var{prompt} -@kindex set monitor-prompt@r{, MIPS remote} +@kindex set monitor-prompt@r{, @acronym{MIPS} remote} @cindex remote monitor prompt Tell @value{GDBN} to expect the specified @var{prompt} string from the remote monitor. The default depends on the target: @@ -19250,23 +20302,23 @@ remote monitor. The default depends on the target: @end table @item show monitor-prompt -@kindex show monitor-prompt@r{, MIPS remote} +@kindex show monitor-prompt@r{, @acronym{MIPS} remote} Show the current strings @value{GDBN} expects as the prompt from the remote monitor. @item set monitor-warnings -@kindex set monitor-warnings@r{, MIPS remote} +@kindex set monitor-warnings@r{, @acronym{MIPS} remote} Enable or disable monitor warnings about hardware breakpoints. This has effect only for the @code{lsi} target. When on, @value{GDBN} will display warning messages whose codes are returned by the @code{lsi} PMON monitor for breakpoint commands. @item show monitor-warnings -@kindex show monitor-warnings@r{, MIPS remote} +@kindex show monitor-warnings@r{, @acronym{MIPS} remote} Show the current setting of printing monitor warnings. @item pmon @var{command} -@kindex pmon@r{, MIPS remote} +@kindex pmon@r{, @acronym{MIPS} remote} @cindex send PMON command This command allows sending an arbitrary @var{command} string to the monitor. The monitor must be in debug mode for this to work. @@ -19787,10 +20839,6 @@ For the Renesas Super-H processor, @value{GDBN} provides these commands: @table @code -@item regs -@kindex regs@r{, Super-H} -Show the values of all Super-H registers. - @item set sh calling-convention @var{convention} @kindex set sh calling-convention Set the calling-convention used when calling functions from @value{GDBN}. @@ -19818,8 +20866,8 @@ This section describes characteristics of architectures that affect all uses of @value{GDBN} with the architecture, both native and cross. @menu +* AArch64:: * i386:: -* A29K:: * Alpha:: * MIPS:: * HPPA:: HP PA architecture @@ -19827,6 +20875,24 @@ all uses of @value{GDBN} with the architecture, both native and cross. * PowerPC:: @end menu +@node AArch64 +@subsection AArch64 +@cindex AArch64 support + +When @value{GDBN} is debugging the AArch64 architecture, it provides the +following special commands: + +@table @code +@item set debug aarch64 +@kindex set debug aarch64 +This command determines whether AArch64 architecture-specific debugging +messages are to be displayed. + +@item show debug aarch64 +Show whether AArch64 debugging messages are displayed. + +@end table + @node i386 @subsection x86 Architecture-specific Issues @@ -19849,56 +20915,30 @@ Show the current setting of the convention to return @code{struct}s from functions. @end table -@node A29K -@subsection A29K - -@table @code - -@kindex set rstack_high_address -@cindex AMD 29K register stack -@cindex register stack, AMD29K -@item set rstack_high_address @var{address} -On AMD 29000 family processors, registers are saved in a separate -@dfn{register stack}. There is no way for @value{GDBN} to determine the -extent of this stack. Normally, @value{GDBN} just assumes that the -stack is ``large enough''. This may result in @value{GDBN} referencing -memory locations that do not exist. If necessary, you can get around -this problem by specifying the ending address of the register stack with -the @code{set rstack_high_address} command. The argument should be an -address, which you probably want to precede with @samp{0x} to specify in -hexadecimal. - -@kindex show rstack_high_address -@item show rstack_high_address -Display the current limit of the register stack, on AMD 29000 family -processors. - -@end table - @node Alpha @subsection Alpha See the following section. @node MIPS -@subsection MIPS +@subsection @acronym{MIPS} @cindex stack on Alpha -@cindex stack on MIPS +@cindex stack on @acronym{MIPS} @cindex Alpha stack -@cindex MIPS stack -Alpha- and MIPS-based computers use an unusual stack frame, which +@cindex @acronym{MIPS} stack +Alpha- and @acronym{MIPS}-based computers use an unusual stack frame, which sometimes requires @value{GDBN} to search backward in the object code to find the beginning of a function. -@cindex response time, MIPS debugging +@cindex response time, @acronym{MIPS} debugging To improve response time (especially for embedded applications, where @value{GDBN} may be restricted to a slow serial line for this search) you may want to limit the size of this search, using one of these commands: @table @code -@cindex @code{heuristic-fence-post} (Alpha, MIPS) +@cindex @code{heuristic-fence-post} (Alpha, @acronym{MIPS}) @item set heuristic-fence-post @var{limit} Restrict @value{GDBN} to examining at most @var{limit} bytes in its search for the beginning of a function. A value of @var{0} (the @@ -19913,16 +20953,16 @@ Display the current limit. @noindent These commands are available @emph{only} when @value{GDBN} is configured -for debugging programs on Alpha or MIPS processors. +for debugging programs on Alpha or @acronym{MIPS} processors. -Several MIPS-specific commands are available when debugging MIPS +Several @acronym{MIPS}-specific commands are available when debugging @acronym{MIPS} programs: @table @code @item set mips abi @var{arg} @kindex set mips abi -@cindex set ABI for MIPS -Tell @value{GDBN} which MIPS ABI is used by the inferior. Possible +@cindex set ABI for @acronym{MIPS} +Tell @value{GDBN} which @acronym{MIPS} ABI is used by the inferior. Possible values of @var{arg} are: @table @samp @@ -19939,7 +20979,39 @@ default). @item show mips abi @kindex show mips abi -Show the MIPS ABI used by @value{GDBN} to debug the inferior. +Show the @acronym{MIPS} ABI used by @value{GDBN} to debug the inferior. + +@item set mips compression @var{arg} +@kindex set mips compression +@cindex code compression, @acronym{MIPS} +Tell @value{GDBN} which @acronym{MIPS} compressed +@acronym{ISA, Instruction Set Architecture} encoding is used by the +inferior. @value{GDBN} uses this for code disassembly and other +internal interpretation purposes. This setting is only referred to +when no executable has been associated with the debugging session or +the executable does not provide information about the encoding it uses. +Otherwise this setting is automatically updated from information +provided by the executable. + +Possible values of @var{arg} are @samp{mips16} and @samp{micromips}. +The default compressed @acronym{ISA} encoding is @samp{mips16}, as +executables containing @acronym{MIPS16} code frequently are not +identified as such. + +This setting is ``sticky''; that is, it retains its value across +debugging sessions until reset either explicitly with this command or +implicitly from an executable. + +The compiler and/or assembler typically add symbol table annotations to +identify functions compiled for the @acronym{MIPS16} or +@acronym{microMIPS} @acronym{ISA}s. If these function-scope annotations +are present, @value{GDBN} uses them in preference to the global +compressed @acronym{ISA} encoding setting. + +@item show mips compression +@kindex show mips compression +Show the @acronym{MIPS} compressed @acronym{ISA} encoding used by +@value{GDBN} to debug the inferior. @item set mipsfpu @itemx show mipsfpu @@ -19947,36 +21019,36 @@ Show the MIPS ABI used by @value{GDBN} to debug the inferior. @item set mips mask-address @var{arg} @kindex set mips mask-address -@cindex MIPS addresses, masking +@cindex @acronym{MIPS} addresses, masking This command determines whether the most-significant 32 bits of 64-bit -MIPS addresses are masked off. The argument @var{arg} can be +@acronym{MIPS} addresses are masked off. The argument @var{arg} can be @samp{on}, @samp{off}, or @samp{auto}. The latter is the default setting, which lets @value{GDBN} determine the correct value. @item show mips mask-address @kindex show mips mask-address -Show whether the upper 32 bits of MIPS addresses are masked off or +Show whether the upper 32 bits of @acronym{MIPS} addresses are masked off or not. @item set remote-mips64-transfers-32bit-regs @kindex set remote-mips64-transfers-32bit-regs -This command controls compatibility with 64-bit MIPS targets that -transfer data in 32-bit quantities. If you have an old MIPS 64 target +This command controls compatibility with 64-bit @acronym{MIPS} targets that +transfer data in 32-bit quantities. If you have an old @acronym{MIPS} 64 target that transfers 32 bits for some registers, like @sc{sr} and @sc{fsr}, and 64 bits for other registers, set this option to @samp{on}. @item show remote-mips64-transfers-32bit-regs @kindex show remote-mips64-transfers-32bit-regs -Show the current setting of compatibility with older MIPS 64 targets. +Show the current setting of compatibility with older @acronym{MIPS} 64 targets. @item set debug mips @kindex set debug mips -This command turns on and off debugging messages for the MIPS-specific +This command turns on and off debugging messages for the @acronym{MIPS}-specific target code in @value{GDBN}. @item show debug mips @kindex show debug mips -Show the current setting of MIPS debugging messages. +Show the current setting of @acronym{MIPS} debugging messages. @end table @@ -20100,6 +21172,7 @@ described here. * Screen Size:: Screen size * Numbers:: Numbers * ABI:: Configuring the current ABI +* Auto-loading:: Automatically loading associated files * Messages/Warnings:: Optional warnings and messages * Debugging Output:: Optional messages about internal happenings * Other Misc Settings:: Other Miscellaneous Settings @@ -20449,6 +21522,7 @@ current ABI. @cindex OS ABI @kindex set osabi @kindex show osabi +@cindex Newlib OS ABI and its influence on the longjmp handling One @value{GDBN} configuration can debug binaries for multiple operating system targets, either via remote debugging or native emulation. @@ -20459,6 +21533,11 @@ an alternate C library (e.g.@: @sc{uClibc} for @sc{gnu}/Linux) which does not have the same identifying marks that the standard C library for your platform provides. +When @value{GDBN} is debugging the AArch64 architecture, it provides a +``Newlib'' OS ABI. This is useful for handling @code{setjmp} and +@code{longjmp} when debugging binaries that use the @sc{newlib} C library. +The ``Newlib'' OS ABI can be selected by @code{set osabi Newlib}. + @table @code @item show osabi Show the OS ABI currently in use. @@ -20525,6 +21604,420 @@ With no argument, show the list of supported C@t{++} ABI's. Set the current C@t{++} ABI to @var{abi}, or return to automatic detection. @end table +@node Auto-loading +@section Automatically loading associated files +@cindex auto-loading + +@value{GDBN} sometimes reads files with commands and settings automatically, +without being explicitly told so by the user. We call this feature +@dfn{auto-loading}. While auto-loading is useful for automatically adapting +@value{GDBN} to the needs of your project, it can sometimes produce unexpected +results or introduce security risks (e.g., if the file comes from untrusted +sources). + +Note that loading of these associated files (including the local @file{.gdbinit} +file) requires accordingly configured @code{auto-load safe-path} +(@pxref{Auto-loading safe path}). + +For these reasons, @value{GDBN} includes commands and options to let you +control when to auto-load files and which files should be auto-loaded. + +@table @code +@anchor{set auto-load off} +@kindex set auto-load off +@item set auto-load off +Globally disable loading of all auto-loaded files. +You may want to use this command with the @samp{-iex} option +(@pxref{Option -init-eval-command}) such as: +@smallexample +$ @kbd{gdb -iex "set auto-load off" untrusted-executable corefile} +@end smallexample + +Be aware that system init file (@pxref{System-wide configuration}) +and init files from your home directory (@pxref{Home Directory Init File}) +still get read (as they come from generally trusted directories). +To prevent @value{GDBN} from auto-loading even those init files, use the +@option{-nx} option (@pxref{Mode Options}), in addition to +@code{set auto-load no}. + +@anchor{show auto-load} +@kindex show auto-load +@item show auto-load +Show whether auto-loading of each specific @samp{auto-load} file(s) is enabled +or disabled. + +@smallexample +(gdb) show auto-load +gdb-scripts: Auto-loading of canned sequences of commands scripts is on. +libthread-db: Auto-loading of inferior specific libthread_db is on. +local-gdbinit: Auto-loading of .gdbinit script from current directory + is on. +python-scripts: Auto-loading of Python scripts is on. +safe-path: List of directories from which it is safe to auto-load files + is $debugdir:$datadir/auto-load. +scripts-directory: List of directories from which to load auto-loaded scripts + is $debugdir:$datadir/auto-load. +@end smallexample + +@anchor{info auto-load} +@kindex info auto-load +@item info auto-load +Print whether each specific @samp{auto-load} file(s) have been auto-loaded or +not. + +@smallexample +(gdb) info auto-load +gdb-scripts: +Loaded Script +Yes /home/user/gdb/gdb-gdb.gdb +libthread-db: No auto-loaded libthread-db. +local-gdbinit: Local .gdbinit file "/home/user/gdb/.gdbinit" has been + loaded. +python-scripts: +Loaded Script +Yes /home/user/gdb/gdb-gdb.py +@end smallexample +@end table + +These are various kinds of files @value{GDBN} can automatically load: + +@itemize @bullet +@item +@xref{objfile-gdb.py file}, controlled by @ref{set auto-load python-scripts}. +@item +@xref{objfile-gdb.gdb file}, controlled by @ref{set auto-load gdb-scripts}. +@item +@xref{dotdebug_gdb_scripts section}, +controlled by @ref{set auto-load python-scripts}. +@item +@xref{Init File in the Current Directory}, +controlled by @ref{set auto-load local-gdbinit}. +@item +@xref{libthread_db.so.1 file}, controlled by @ref{set auto-load libthread-db}. +@end itemize + +These are @value{GDBN} control commands for the auto-loading: + +@multitable @columnfractions .5 .5 +@item @xref{set auto-load off}. +@tab Disable auto-loading globally. +@item @xref{show auto-load}. +@tab Show setting of all kinds of files. +@item @xref{info auto-load}. +@tab Show state of all kinds of files. +@item @xref{set auto-load gdb-scripts}. +@tab Control for @value{GDBN} command scripts. +@item @xref{show auto-load gdb-scripts}. +@tab Show setting of @value{GDBN} command scripts. +@item @xref{info auto-load gdb-scripts}. +@tab Show state of @value{GDBN} command scripts. +@item @xref{set auto-load python-scripts}. +@tab Control for @value{GDBN} Python scripts. +@item @xref{show auto-load python-scripts}. +@tab Show setting of @value{GDBN} Python scripts. +@item @xref{info auto-load python-scripts}. +@tab Show state of @value{GDBN} Python scripts. +@item @xref{set auto-load scripts-directory}. +@tab Control for @value{GDBN} auto-loaded scripts location. +@item @xref{show auto-load scripts-directory}. +@tab Show @value{GDBN} auto-loaded scripts location. +@item @xref{set auto-load local-gdbinit}. +@tab Control for init file in the current directory. +@item @xref{show auto-load local-gdbinit}. +@tab Show setting of init file in the current directory. +@item @xref{info auto-load local-gdbinit}. +@tab Show state of init file in the current directory. +@item @xref{set auto-load libthread-db}. +@tab Control for thread debugging library. +@item @xref{show auto-load libthread-db}. +@tab Show setting of thread debugging library. +@item @xref{info auto-load libthread-db}. +@tab Show state of thread debugging library. +@item @xref{set auto-load safe-path}. +@tab Control directories trusted for automatic loading. +@item @xref{show auto-load safe-path}. +@tab Show directories trusted for automatic loading. +@item @xref{add-auto-load-safe-path}. +@tab Add directory trusted for automatic loading. +@end multitable + +@menu +* Init File in the Current Directory:: @samp{set/show/info auto-load local-gdbinit} +* libthread_db.so.1 file:: @samp{set/show/info auto-load libthread-db} +* objfile-gdb.gdb file:: @samp{set/show/info auto-load gdb-script} +* Auto-loading safe path:: @samp{set/show/info auto-load safe-path} +* Auto-loading verbose mode:: @samp{set/show debug auto-load} +@xref{Python Auto-loading}. +@end menu + +@node Init File in the Current Directory +@subsection Automatically loading init file in the current directory +@cindex auto-loading init file in the current directory + +By default, @value{GDBN} reads and executes the canned sequences of commands +from init file (if any) in the current working directory, +see @ref{Init File in the Current Directory during Startup}. + +Note that loading of this local @file{.gdbinit} file also requires accordingly +configured @code{auto-load safe-path} (@pxref{Auto-loading safe path}). + +@table @code +@anchor{set auto-load local-gdbinit} +@kindex set auto-load local-gdbinit +@item set auto-load local-gdbinit [on|off] +Enable or disable the auto-loading of canned sequences of commands +(@pxref{Sequences}) found in init file in the current directory. + +@anchor{show auto-load local-gdbinit} +@kindex show auto-load local-gdbinit +@item show auto-load local-gdbinit +Show whether auto-loading of canned sequences of commands from init file in the +current directory is enabled or disabled. + +@anchor{info auto-load local-gdbinit} +@kindex info auto-load local-gdbinit +@item info auto-load local-gdbinit +Print whether canned sequences of commands from init file in the +current directory have been auto-loaded. +@end table + +@node libthread_db.so.1 file +@subsection Automatically loading thread debugging library +@cindex auto-loading libthread_db.so.1 + +This feature is currently present only on @sc{gnu}/Linux native hosts. + +@value{GDBN} reads in some cases thread debugging library from places specific +to the inferior (@pxref{set libthread-db-search-path}). + +The special @samp{libthread-db-search-path} entry @samp{$sdir} is processed +without checking this @samp{set auto-load libthread-db} switch as system +libraries have to be trusted in general. In all other cases of +@samp{libthread-db-search-path} entries @value{GDBN} checks first if @samp{set +auto-load libthread-db} is enabled before trying to open such thread debugging +library. + +Note that loading of this debugging library also requires accordingly configured +@code{auto-load safe-path} (@pxref{Auto-loading safe path}). + +@table @code +@anchor{set auto-load libthread-db} +@kindex set auto-load libthread-db +@item set auto-load libthread-db [on|off] +Enable or disable the auto-loading of inferior specific thread debugging library. + +@anchor{show auto-load libthread-db} +@kindex show auto-load libthread-db +@item show auto-load libthread-db +Show whether auto-loading of inferior specific thread debugging library is +enabled or disabled. + +@anchor{info auto-load libthread-db} +@kindex info auto-load libthread-db +@item info auto-load libthread-db +Print the list of all loaded inferior specific thread debugging libraries and +for each such library print list of inferior @var{pid}s using it. +@end table + +@node objfile-gdb.gdb file +@subsection The @file{@var{objfile}-gdb.gdb} file +@cindex auto-loading @file{@var{objfile}-gdb.gdb} + +@value{GDBN} tries to load an @file{@var{objfile}-gdb.gdb} file containing +canned sequences of commands (@pxref{Sequences}), as long as @samp{set +auto-load gdb-scripts} is set to @samp{on}. + +Note that loading of this script file also requires accordingly configured +@code{auto-load safe-path} (@pxref{Auto-loading safe path}). + +For more background refer to the similar Python scripts auto-loading +description (@pxref{objfile-gdb.py file}). + +@table @code +@anchor{set auto-load gdb-scripts} +@kindex set auto-load gdb-scripts +@item set auto-load gdb-scripts [on|off] +Enable or disable the auto-loading of canned sequences of commands scripts. + +@anchor{show auto-load gdb-scripts} +@kindex show auto-load gdb-scripts +@item show auto-load gdb-scripts +Show whether auto-loading of canned sequences of commands scripts is enabled or +disabled. + +@anchor{info auto-load gdb-scripts} +@kindex info auto-load gdb-scripts +@cindex print list of auto-loaded canned sequences of commands scripts +@item info auto-load gdb-scripts [@var{regexp}] +Print the list of all canned sequences of commands scripts that @value{GDBN} +auto-loaded. +@end table + +If @var{regexp} is supplied only canned sequences of commands scripts with +matching names are printed. + +@node Auto-loading safe path +@subsection Security restriction for auto-loading +@cindex auto-loading safe-path + +As the files of inferior can come from untrusted source (such as submitted by +an application user) @value{GDBN} does not always load any files automatically. +@value{GDBN} provides the @samp{set auto-load safe-path} setting to list +directories trusted for loading files not explicitly requested by user. +Each directory can also be a shell wildcard pattern. + +If the path is not set properly you will see a warning and the file will not +get loaded: + +@smallexample +$ ./gdb -q ./gdb +Reading symbols from /home/user/gdb/gdb...done. +warning: File "/home/user/gdb/gdb-gdb.gdb" auto-loading has been + declined by your `auto-load safe-path' set + to "$debugdir:$datadir/auto-load". +warning: File "/home/user/gdb/gdb-gdb.py" auto-loading has been + declined by your `auto-load safe-path' set + to "$debugdir:$datadir/auto-load". +@end smallexample + +@noindent +To instruct @value{GDBN} to go ahead and use the init files anyway, +invoke @value{GDBN} like this: + +@smallexample +$ gdb -q -iex "set auto-load safe-path /home/user/gdb" ./gdb +@end smallexample + +The list of trusted directories is controlled by the following commands: + +@table @code +@anchor{set auto-load safe-path} +@kindex set auto-load safe-path +@item set auto-load safe-path @r{[}@var{directories}@r{]} +Set the list of directories (and their subdirectories) trusted for automatic +loading and execution of scripts. You can also enter a specific trusted file. +Each directory can also be a shell wildcard pattern; wildcards do not match +directory separator - see @code{FNM_PATHNAME} for system function @code{fnmatch} +(@pxref{Wildcard Matching, fnmatch, , libc, GNU C Library Reference Manual}). +If you omit @var{directories}, @samp{auto-load safe-path} will be reset to +its default value as specified during @value{GDBN} compilation. + +The list of directories uses path separator (@samp{:} on GNU and Unix +systems, @samp{;} on MS-Windows and MS-DOS) to separate directories, similarly +to the @env{PATH} environment variable. + +@anchor{show auto-load safe-path} +@kindex show auto-load safe-path +@item show auto-load safe-path +Show the list of directories trusted for automatic loading and execution of +scripts. + +@anchor{add-auto-load-safe-path} +@kindex add-auto-load-safe-path +@item add-auto-load-safe-path +Add an entry (or list of entries) the list of directories trusted for automatic +loading and execution of scripts. Multiple entries may be delimited by the +host platform path separator in use. +@end table + +This variable defaults to what @code{--with-auto-load-dir} has been configured +to (@pxref{with-auto-load-dir}). @file{$debugdir} and @file{$datadir} +substitution applies the same as for @ref{set auto-load scripts-directory}. +The default @code{set auto-load safe-path} value can be also overriden by +@value{GDBN} configuration option @option{--with-auto-load-safe-path}. + +Setting this variable to @file{/} disables this security protection, +corresponding @value{GDBN} configuration option is +@option{--without-auto-load-safe-path}. +This variable is supposed to be set to the system directories writable by the +system superuser only. Users can add their source directories in init files in +their home directories (@pxref{Home Directory Init File}). See also deprecated +init file in the current directory +(@pxref{Init File in the Current Directory during Startup}). + +To force @value{GDBN} to load the files it declined to load in the previous +example, you could use one of the following ways: + +@table @asis +@item @file{~/.gdbinit}: @samp{add-auto-load-safe-path ~/src/gdb} +Specify this trusted directory (or a file) as additional component of the list. +You have to specify also any existing directories displayed by +by @samp{show auto-load safe-path} (such as @samp{/usr:/bin} in this example). + +@item @kbd{gdb -iex "set auto-load safe-path /usr:/bin:~/src/gdb" @dots{}} +Specify this directory as in the previous case but just for a single +@value{GDBN} session. + +@item @kbd{gdb -iex "set auto-load safe-path /" @dots{}} +Disable auto-loading safety for a single @value{GDBN} session. +This assumes all the files you debug during this @value{GDBN} session will come +from trusted sources. + +@item @kbd{./configure --without-auto-load-safe-path} +During compilation of @value{GDBN} you may disable any auto-loading safety. +This assumes all the files you will ever debug with this @value{GDBN} come from +trusted sources. +@end table + +On the other hand you can also explicitly forbid automatic files loading which +also suppresses any such warning messages: + +@table @asis +@item @kbd{gdb -iex "set auto-load no" @dots{}} +You can use @value{GDBN} command-line option for a single @value{GDBN} session. + +@item @file{~/.gdbinit}: @samp{set auto-load no} +Disable auto-loading globally for the user +(@pxref{Home Directory Init File}). While it is improbable, you could also +use system init file instead (@pxref{System-wide configuration}). +@end table + +This setting applies to the file names as entered by user. If no entry matches +@value{GDBN} tries as a last resort to also resolve all the file names into +their canonical form (typically resolving symbolic links) and compare the +entries again. @value{GDBN} already canonicalizes most of the filenames on its +own before starting the comparison so a canonical form of directories is +recommended to be entered. + +@node Auto-loading verbose mode +@subsection Displaying files tried for auto-load +@cindex auto-loading verbose mode + +For better visibility of all the file locations where you can place scripts to +be auto-loaded with inferior --- or to protect yourself against accidental +execution of untrusted scripts --- @value{GDBN} provides a feature for printing +all the files attempted to be loaded. Both existing and non-existing files may +be printed. + +For example the list of directories from which it is safe to auto-load files +(@pxref{Auto-loading safe path}) applies also to canonicalized filenames which +may not be too obvious while setting it up. + +@smallexample +(gdb) set debug auto-load on +(gdb) file ~/src/t/true +auto-load: Loading canned sequences of commands script "/tmp/true-gdb.gdb" + for objfile "/tmp/true". +auto-load: Updating directories of "/usr:/opt". +auto-load: Using directory "/usr". +auto-load: Using directory "/opt". +warning: File "/tmp/true-gdb.gdb" auto-loading has been declined + by your `auto-load safe-path' set to "/usr:/opt". +@end smallexample + +@table @code +@anchor{set debug auto-load} +@kindex set debug auto-load +@item set debug auto-load [on|off] +Set whether to print the filenames attempted to be auto-loaded. + +@anchor{show debug auto-load} +@kindex show debug auto-load +@item show debug auto-load +Show whether printing of the filenames attempted to be auto-loaded is turned +on or off. +@end table + @node Messages/Warnings @section Optional Warnings and Messages @@ -20643,11 +22136,18 @@ asynchronous command finishes its execution. The default is off. Displays the current setting of asynchronous command completion notification. @kindex set debug +@cindex ARM AArch64 +@item set debug aarch64 +Turns on or off display of debugging messages related to ARM AArch64. +The default is off. +@kindex show debug +@item show debug aarch64 +Displays the current state of displaying debugging messages related to +ARM AArch64. @cindex gdbarch debugging info @cindex architecture debugging info @item set debug arch Turns on or off display of gdbarch debugging info. The default is off -@kindex show debug @item show debug arch Displays the current state of displaying gdbarch debugging info. @item set debug aix-thread @@ -20666,6 +22166,13 @@ When enabled, this setting causes @value{GDBN} to compute the names both ways and display any discrepancies. @item show debug check-physname Show the current state of ``physname'' checking. +@item set debug coff-pe-read +@cindex COFF/PE exported symbols +Control display of debugging messages related to reading of COFF/PE +exported symbols. The default is off. +@item show debug coff-pe-read +Displays the current state of displaying debugging messages related to +reading of COFF/PE exported symbols. @item set debug dwarf2-die @cindex DWARF2 DIEs Dump DWARF2 DIEs after they are read in. @@ -20673,6 +22180,12 @@ The value is the number of nesting levels to print. A value of zero turns off the display. @item show debug dwarf2-die Show the current state of DWARF2 DIE debugging. +@item set debug dwarf2-read +@cindex DWARF2 Reading +Turns on or off display of debugging messages related to reading +DWARF debug info. The default is off. +@item show debug dwarf2-read +Show the current state of DWARF2 reader debugging. @item set debug displaced @cindex displaced stepping debugging info Turns on or off display of @value{GDBN} debugging info for the @@ -20724,6 +22237,19 @@ Displays the current state of @value{GDBN} JIT debugging. Turns on or off debugging messages from the Linux LWP debug support. @item show debug lin-lwp Show the current state of Linux LWP debugging messages. +@item set debug mach-o +@cindex Mach-O symbols processing +Control display of debugging messages related to Mach-O symbols +processing. The default is off. +@item show debug mach-o +Displays the current state of displaying debugging messages related to +reading of COFF/PE exported symbols. +@item set debug notification +@cindex remote async notification debugging info +Turns on or off debugging messages about remote async notification. +The default is off. +@item show debug notification +Displays the current state of remote async notification debugging messages. @item set debug observer @cindex observer debugging info Turns on or off display of @value{GDBN} observer debugging. This @@ -20770,6 +22296,12 @@ Turns on or off debugging messages for FR-V shared-library code. @item show debug solib-frv Display the current state of FR-V shared-library code debugging messages. +@item set debug symtab-create +@cindex symbol table creation +Turns on or off display of debugging messages related to symbol table creation. +The default is off. +@item show debug symtab-create +Show the current state of symbol table creation debugging. @item set debug target @cindex target debugging info Turns on or off display of @value{GDBN} target debugging info. This info @@ -20974,8 +22506,9 @@ command should not be repeated when the user hits @key{RET} @kindex help user-defined @item help user-defined -List all user-defined commands, with the first line of the documentation -(if any) for each. +List all user-defined commands and all python commands defined in class +COMAND_USER. The first line of the documentation or docstring is +included (if any). @kindex show user @item show user @@ -20983,6 +22516,7 @@ List all user-defined commands, with the first line of the documentation Display the @value{GDBN} commands used to define @var{commandname} (but not its documentation). If no @var{commandname} is given, display the definitions for all user-defined commands. +This does not work for user-defined python commands. @cindex infinite recursion in user-defined commands @kindex show max-user-call-depth @@ -20992,6 +22526,7 @@ definitions for all user-defined commands. The value of @code{max-user-call-depth} controls how many recursion levels are allowed in user-defined commands before @value{GDBN} suspects an infinite recursion and aborts the command. +This does not apply to user-defined python commands. @end table In addition to the above commands, user-defined commands frequently @@ -21396,7 +22931,7 @@ automatically imported when @value{GDBN} starts. @menu * Python Commands:: Accessing Python from @value{GDBN}. * Python API:: Accessing @value{GDBN} from Python. -* Auto-loading:: Automatically loading Python code. +* Python Auto-loading:: Automatically loading Python code. * Python modules:: Python modules provided by @value{GDBN}. @end menu @@ -21405,12 +22940,31 @@ automatically imported when @value{GDBN} starts. @cindex python commands @cindex commands to access python -@value{GDBN} provides one command for accessing the Python interpreter, +@value{GDBN} provides two commands for accessing the Python interpreter, and one related setting: @table @code +@kindex python-interactive +@kindex pi +@item python-interactive @r{[}@var{command}@r{]} +@itemx pi @r{[}@var{command}@r{]} +Without an argument, the @code{python-interactive} command can be used +to start an interactive Python prompt. To return to @value{GDBN}, +type the @code{EOF} character (e.g., @kbd{Ctrl-D} on an empty prompt). + +Alternatively, a single-line Python command can be given as an +argument and evaluated. If the command is an expression, the result +will be printed; otherwise, nothing will be printed. For example: + +@smallexample +(@value{GDBP}) python-interactive 2 + 3 +5 +@end smallexample + @kindex python -@item python @r{[}@var{code}@r{]} +@kindex py +@item python @r{[}@var{command}@r{]} +@itemx py @r{[}@var{command}@r{]} The @code{python} command can be used to evaluate Python code. If given an argument, the @code{python} command will evaluate the @@ -21481,6 +23035,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. * Pretty Printing API:: Pretty-printing values. * Selecting Pretty-Printers:: How GDB chooses a pretty-printer. * Writing a Pretty-Printer:: Writing a Pretty-Printer. +* Type Printing API:: Pretty-printing types. * Inferiors In Python:: Python representation of inferiors (processes) * Events In Python:: Listening for events from @value{GDBN}. * Threads In Python:: Accessing inferior threads from Python. @@ -21493,10 +23048,11 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. * Blocks In Python:: Accessing frame blocks from Python. * Symbols In Python:: Python representation of symbols. * Symbol Tables In Python:: Python representation of symbol tables. -* Lazy Strings In Python:: Python representation of lazy strings. * Breakpoints In Python:: Manipulating breakpoints using Python. * Finish Breakpoints in Python:: Setting Breakpoints on function return using Python. +* Lazy Strings In Python:: Python representation of lazy strings. +* Architectures In Python:: Python representation of architectures. @end menu @node Basic Python @@ -21581,6 +23137,15 @@ compute values, for example, it is the only way to get the value of a convenience variable (@pxref{Convenience Vars}) as a @code{gdb.Value}. @end defun +@findex gdb.find_pc_line +@defun gdb.find_pc_line (pc) +Return the @code{gdb.Symtab_and_line} object corresponding to the +@var{pc} value. @xref{Symbol Tables In Python}. If an invalid +value of @var{pc} is passed as an argument, then the @code{symtab} and +@code{line} attributes of the returned @code{gdb.Symtab_and_line} object +will be @code{None} and 0 respectively. +@end defun + @findex gdb.post_event @defun gdb.post_event (event) Put @var{event}, a callable object taking no arguments, into @@ -21792,7 +23357,7 @@ to handle this case. Example: >class HelloWorld (gdb.Command): > """Greet the whole world.""" > def __init__ (self): -> super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_OBSCURE) +> super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_USER) > def invoke (self, args, from_tty): > argv = gdb.string_to_argv (args) > if len (argv) != 0: @@ -21856,7 +23421,6 @@ Any values returned from a function call will be stored as a The following attributes are provided: -@table @code @defvar Value.address If this object is addressable, this read-only attribute holds a @code{gdb.Value} object representing the address. Otherwise, @@ -21904,11 +23468,9 @@ The value of @code{somevar} is not fetched at this time. It will be fetched when the value is needed, or when the @code{fetch_lazy} method is invoked. @end defvar -@end table The following methods are provided: -@table @code @defun Value.__init__ (@var{val}) Many Python values can be converted directly to a @code{gdb.Value} via this object initializer. Specifically: @@ -21970,6 +23532,79 @@ bar = foo.dereference () The result @code{bar} will be a @code{gdb.Value} object holding the value pointed to by @code{foo}. + +A similar function @code{Value.referenced_value} exists which also +returns @code{gdb.Value} objects corresonding to the values pointed to +by pointer values (and additionally, values referenced by reference +values). However, the behavior of @code{Value.dereference} +differs from @code{Value.referenced_value} by the fact that the +behavior of @code{Value.dereference} is identical to applying the C +unary operator @code{*} on a given value. For example, consider a +reference to a pointer @code{ptrref}, declared in your C@t{++} program +as + +@smallexample +typedef int *intptr; +... +int val = 10; +intptr ptr = &val; +intptr &ptrref = ptr; +@end smallexample + +Though @code{ptrref} is a reference value, one can apply the method +@code{Value.dereference} to the @code{gdb.Value} object corresponding +to it and obtain a @code{gdb.Value} which is identical to that +corresponding to @code{val}. However, if you apply the method +@code{Value.referenced_value}, the result would be a @code{gdb.Value} +object identical to that corresponding to @code{ptr}. + +@smallexample +py_ptrref = gdb.parse_and_eval ("ptrref") +py_val = py_ptrref.dereference () +py_ptr = py_ptrref.referenced_value () +@end smallexample + +The @code{gdb.Value} object @code{py_val} is identical to that +corresponding to @code{val}, and @code{py_ptr} is identical to that +corresponding to @code{ptr}. In general, @code{Value.dereference} can +be applied whenever the C unary operator @code{*} can be applied +to the corresponding C value. For those cases where applying both +@code{Value.dereference} and @code{Value.referenced_value} is allowed, +the results obtained need not be identical (as we have seen in the above +example). The results are however identical when applied on +@code{gdb.Value} objects corresponding to pointers (@code{gdb.Value} +objects with type code @code{TYPE_CODE_PTR}) in a C/C@t{++} program. +@end defun + +@defun Value.referenced_value () +For pointer or reference data types, this method returns a new +@code{gdb.Value} object corresponding to the value referenced by the +pointer/reference value. For pointer data types, +@code{Value.dereference} and @code{Value.referenced_value} produce +identical results. The difference between these methods is that +@code{Value.dereference} cannot get the values referenced by reference +values. For example, consider a reference to an @code{int}, declared +in your C@t{++} program as + +@smallexample +int val = 10; +int &ref = val; +@end smallexample + +@noindent +then applying @code{Value.dereference} to the @code{gdb.Value} object +corresponding to @code{ref} will result in an error, while applying +@code{Value.referenced_value} will result in a @code{gdb.Value} object +identical to that corresponding to @code{val}. + +@smallexample +py_ref = gdb.parse_and_eval ("ref") +er_ref = py_ref.dereference () # Results in error +py_val = py_ref.referenced_value () # Returns the referenced value +@end smallexample + +The @code{gdb.Value} object @code{py_val} is identical to that +corresponding to @code{val}. @end defun @defun Value.dynamic_cast (type) @@ -22050,7 +23685,6 @@ has no effect. This method does not return a value. @end defun -@end table @node Types In Python @subsubsection Types In Python @@ -22091,7 +23725,6 @@ description of the @code{Type.fields} method for a description of the An instance of @code{Type} has the following attributes: -@table @code @defvar Type.code The type code for this type. The type code will be one of the @code{TYPE_CODE_} constants defined below. @@ -22109,11 +23742,9 @@ The tag name for this type. The tag name is the name after languages have this concept. If this type has no tag name, then @code{None} is returned. @end defvar -@end table The following methods are provided: -@table @code @defun Type.fields () For structure and union types, this method returns the fields. Range types have two fields, the minimum and maximum values. Enum types @@ -22164,6 +23795,19 @@ second argument is the upper bound of the array. An array's length must not be negative, but the bounds can be. @end defun +@defun Type.vector (@var{n1} @r{[}, @var{n2}@r{]}) +Return a new @code{gdb.Type} object which represents a vector of this +type. If one argument is given, it is the inclusive upper bound of +the vector; in this case the lower bound is zero. If two arguments are +given, the first argument is the lower bound of the vector, and the +second argument is the upper bound of the vector. A vector's length +must not be negative, but the bounds can be. + +The difference between an @code{array} and a @code{vector} is that +arrays behave like in C: when used in expressions they decay to a pointer +to the first element whereas vectors are treated as first class values. +@end defun + @defun Type.const () Return a new @code{gdb.Type} object which represents a @code{const}-qualified variant of this type. @@ -22228,7 +23872,6 @@ exception. Ordinarily, only C@t{++} code will have template types. If @var{block} is given, then @var{name} is looked up in that scope. Otherwise, it is searched for globally. @end defun -@end table Each type has a code, which indicates what category this type falls @@ -22305,7 +23948,7 @@ language-defined string types; C strings are not represented this way. @findex TYPE_CODE_BITSTRING @findex gdb.TYPE_CODE_BITSTRING @item gdb.TYPE_CODE_BITSTRING -A string of bits. +A string of bits. It is deprecated. @findex TYPE_CODE_ERROR @findex gdb.TYPE_CODE_ERROR @@ -22565,7 +24208,7 @@ This practice will enable @value{GDBN} to load multiple versions of your pretty-printers at the same time, because they will have different names. -You should write auto-loaded code (@pxref{Auto-loading}) such that it +You should write auto-loaded code (@pxref{Python Auto-loading}) such that it can be evaluated multiple times without changing its meaning. An ideal auto-load file will consist solely of @code{import}s of your printer modules, followed by a call to a register pretty-printers with @@ -22681,6 +24324,68 @@ my_library.so: bar @end smallexample +@node Type Printing API +@subsubsection Type Printing API +@cindex type printing API for Python + +@value{GDBN} provides a way for Python code to customize type display. +This is mainly useful for substituting canonical typedef names for +types. + +@cindex type printer +A @dfn{type printer} is just a Python object conforming to a certain +protocol. A simple base class implementing the protocol is provided; +see @ref{gdb.types}. A type printer must supply at least: + +@defivar type_printer enabled +A boolean which is True if the printer is enabled, and False +otherwise. This is manipulated by the @code{enable type-printer} +and @code{disable type-printer} commands. +@end defivar + +@defivar type_printer name +The name of the type printer. This must be a string. This is used by +the @code{enable type-printer} and @code{disable type-printer} +commands. +@end defivar + +@defmethod type_printer instantiate (self) +This is called by @value{GDBN} at the start of type-printing. It is +only called if the type printer is enabled. This method must return a +new object that supplies a @code{recognize} method, as described below. +@end defmethod + + +When displaying a type, say via the @code{ptype} command, @value{GDBN} +will compute a list of type recognizers. This is done by iterating +first over the per-objfile type printers (@pxref{Objfiles In Python}), +followed by the per-progspace type printers (@pxref{Progspaces In +Python}), and finally the global type printers. + +@value{GDBN} will call the @code{instantiate} method of each enabled +type printer. If this method returns @code{None}, then the result is +ignored; otherwise, it is appended to the list of recognizers. + +Then, when @value{GDBN} is going to display a type name, it iterates +over the list of recognizers. For each one, it calls the recognition +function, stopping if the function returns a non-@code{None} value. +The recognition function is defined as: + +@defmethod type_recognizer recognize (self, type) +If @var{type} is not recognized, return @code{None}. Otherwise, +return a string which is to be printed as the name of @var{type}. +@var{type} will be an instance of @code{gdb.Type} (@pxref{Types In +Python}). +@end defmethod + +@value{GDBN} uses this two-pass approach so that type printers can +efficiently cache information without holding on to it too long. For +example, it can be convenient to look up type information in a type +printer and hold it for a recognizer's lifetime; if a single pass were +done then type printers would have to make use of the event system in +order to avoid holding information that could become stale as the +inferior changed. + @node Inferiors In Python @subsubsection Inferiors In Python @cindex inferiors in Python @@ -22704,7 +24409,6 @@ Return an object representing the current inferior. A @code{gdb.Inferior} object has the following attributes: -@table @code @defvar Inferior.num ID of inferior, as assigned by GDB. @end defvar @@ -22718,11 +24422,9 @@ system. Boolean signaling whether the inferior was created using `attach', or started by @value{GDBN} itself. @end defvar -@end table A @code{gdb.Inferior} object has the following methods: -@table @code @defun Inferior.is_valid () Returns @code{True} if the @code{gdb.Inferior} object is valid, @code{False} if not. A @code{gdb.Inferior} object will become invalid @@ -22737,20 +24439,21 @@ when it is called. If there are no valid threads, the method will return an empty tuple. @end defun -@findex gdb.read_memory +@findex Inferior.read_memory @defun Inferior.read_memory (address, 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. +or a string. It can be modified and given to the +@code{Inferior.write_memory} function. In @code{Python} 3, the return +value is a @code{memoryview} object. @end defun -@findex gdb.write_memory +@findex Inferior.write_memory @defun Inferior.write_memory (address, buffer @r{[}, length@r{]}) Write the contents of @var{buffer} to the inferior, starting at @var{address}. The @var{buffer} parameter must be a Python object which supports the buffer protocol, i.e., a string, an array or the -object returned from @code{gdb.read_memory}. If given, @var{length} +object returned from @code{Inferior.read_memory}. If given, @var{length} determines the number of bytes from @var{buffer} to be written. @end defun @@ -22764,7 +24467,6 @@ object returned from @code{gdb.read_memory}. Returns a Python @code{Long} containing the address where the pattern was found, or @code{None} if the pattern could not be found. @end defun -@end table @node Events In Python @subsubsection Events In Python @@ -22783,7 +24485,6 @@ with an @dfn{event registry}. An event registry is an object in the @code{gdb.events} module which dispatches particular events. A registry provides methods to register and unregister event handlers: -@table @code @defun EventRegistry.connect (object) Add the given callable @var{object} to the registry. This object will be called when an event corresponding to this registry occurs. @@ -22793,7 +24494,6 @@ called when an event corresponding to this registry occurs. Remove the given @var{object} from the registry. Once removed, the object will no longer receive notifications of events. @end defun -@end table Here is an example: @@ -22827,12 +24527,10 @@ events which are emitted by this or other modules might extend this event. Examples of these events are @code{gdb.BreakpointEvent} and @code{gdb.ContinueEvent}. -@table @code @defvar ThreadEvent.inferior_thread In non-stop mode this attribute will be set to the specific thread which was involved in the emitted event. Otherwise, it will be set to @code{None}. @end defvar -@end table Emits @code{gdb.ContinueEvent} which extends @code{gdb.ThreadEvent}. @@ -22842,7 +24540,6 @@ inherited attribute refer to @code{gdb.ThreadEvent} above. @item events.exited Emits @code{events.ExitedEvent} which indicates that the inferior has exited. @code{events.ExitedEvent} has two attributes: -@table @code @defvar ExitedEvent.exit_code An integer representing the exit code, if available, which the inferior has returned. (The exit code could be unavailable if, for example, @@ -22852,7 +24549,6 @@ the attribute does not exist. @defvar ExitedEvent inferior A reference to the inferior which triggered the @code{exited} event. @end defvar -@end table @item events.stop Emits @code{gdb.StopEvent} which extends @code{gdb.ThreadEvent}. @@ -22867,20 +24563,17 @@ Emits @code{gdb.SignalEvent} which extends @code{gdb.StopEvent}. This event indicates that the inferior or one of its threads has received as signal. @code{gdb.SignalEvent} has the following attributes: -@table @code @defvar SignalEvent.stop_signal A string representing the signal received by the inferior. A list of possible signal values can be obtained by running the command @code{info signals} in the @value{GDBN} command prompt. @end defvar -@end table Also emits @code{gdb.BreakpointEvent} which extends @code{gdb.StopEvent}. @code{gdb.BreakpointEvent} event indicates that one or more breakpoints have been hit, and has the following attributes: -@table @code @defvar BreakpointEvent.breakpoints A sequence containing references to all the breakpoints (type @code{gdb.Breakpoint}) that were hit. @@ -22891,18 +24584,15 @@ A reference to the first breakpoint that was hit. This function is maintained for backward compatibility and is now deprecated in favor of the @code{gdb.BreakpointEvent.breakpoints} attribute. @end defvar -@end table @item events.new_objfile Emits @code{gdb.NewObjFileEvent} which indicates that a new object file has been loaded by @value{GDBN}. @code{gdb.NewObjFileEvent} has one attribute: -@table @code @defvar NewObjFileEvent.new_objfile A reference to the object file (@code{gdb.Objfile}) which has been loaded. @xref{Objfiles In Python}, for details of the @code{gdb.Objfile} object. @end defvar -@end table @end table @@ -22925,7 +24615,6 @@ is no selected thread, this will return @code{None}. A @code{gdb.InferiorThread} object has the following attributes: -@table @code @defvar InferiorThread.name The name of the thread. If the user specified a name using @code{thread name}, then this returns that name. Otherwise, if an @@ -22948,11 +24637,9 @@ is the Lightweight Process ID (LWPID), and the third is the Thread ID (TID). Either the LWPID or TID may be 0, which indicates that the operating system does not use that identifier. @end defvar -@end table A @code{gdb.InferiorThread} object has the following methods: -@table @code @defun InferiorThread.is_valid () Returns @code{True} if the @code{gdb.InferiorThread} object is valid, @code{False} if not. A @code{gdb.InferiorThread} object will become @@ -22977,7 +24664,6 @@ Return a Boolean indicating whether the thread is running. @defun InferiorThread.is_exited () Return a Boolean indicating whether the thread is exited. @end defun -@end table @node Commands In Python @subsubsection Commands In Python @@ -23171,6 +24857,15 @@ The command has to do with tracepoints. For example, @code{trace}, @kbd{help tracepoints} at the @value{GDBN} prompt to see a list of commands in this category. +@findex COMMAND_USER +@findex gdb.COMMAND_USER +@item gdb.COMMAND_USER +The command is a general purpose command for the user, and typically +does not fit in one of the other categories. +Type @kbd{help user-defined} at the @value{GDBN} prompt to see +a list of commands in this category, as well as the list of gdb macros +(@pxref{Sequences}). + @findex COMMAND_OBSCURE @findex gdb.COMMAND_OBSCURE @item gdb.COMMAND_OBSCURE @@ -23232,7 +24927,7 @@ class HelloWorld (gdb.Command): """Greet the whole world.""" def __init__ (self): - super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_OBSCURE) + super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_USER) def invoke (self, arg, from_tty): print "Hello, World!" @@ -23466,6 +25161,13 @@ 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. +Now you can use the function in an expression: + +@smallexample +(gdb) print $greet("Bob") +$1 = "Hello, Bob!" +@end smallexample + @node Progspaces In Python @subsubsection Program Spaces In Python @@ -23509,6 +25211,11 @@ which is used to format the value. @xref{Pretty Printing API}, for more information. @end defvar +@defvar Progspace.type_printers +The @code{type_printers} attribute is a list of type printer objects. +@xref{Type Printing API}, for more information. +@end defvar + @node Objfiles In Python @subsubsection Objfiles In Python @@ -23526,7 +25233,7 @@ The following objfile-related functions are available in the @findex gdb.current_objfile @defun gdb.current_objfile () -When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} +When auto-loading a Python script (@pxref{Python 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}. @@ -23554,6 +25261,11 @@ which is used to format the value. @xref{Pretty Printing API}, for more information. @end defvar +@defvar Objfile.type_printers +The @code{type_printers} attribute is a list of type printer objects. +@xref{Type Printing API}, for more information. +@end defvar + A @code{gdb.Objfile} object has the following methods: @defun Objfile.is_valid () @@ -23603,7 +25315,6 @@ frames, as expressed by the given @var{reason} code (an integer, see the A @code{gdb.Frame} object has the following methods: -@table @code @defun 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 @@ -23616,6 +25327,11 @@ Returns the function name of the frame, or @code{None} if it can't be obtained. @end defun +@defun Frame.architecture () +Returns the @code{gdb.Architecture} object corresponding to the frame's +architecture. @xref{Architectures In Python}. +@end defun + @defun Frame.type () Returns the type of the frame. The value can be one of: @table @code @@ -23737,7 +25453,6 @@ must be a string or a @code{gdb.Symbol} object. @var{block} must be a Set this frame to be the selected frame. @xref{Stack, ,Examining the Stack}. @end defun -@end table @node Blocks In Python @subsubsection Accessing frame blocks from Python. @@ -23753,6 +25468,13 @@ frames. Furthermore, see @ref{Stack, ,Examining the Stack}, for more detailed technical information on @value{GDBN}'s book-keeping of the stack. +A @code{gdb.Block} is iterable. The iterator returns the symbols +(@pxref{Symbols In Python}) local to the block. Python programs +should not assume that a specific block object will always contain a +given symbol, since changes in @value{GDBN} features and +infrastructure may cause symbols move across blocks in a symbol +table. + The following block-related functions are available in the @code{gdb} module: @@ -23765,21 +25487,17 @@ will return @code{None}. A @code{gdb.Block} object has the following methods: -@table @code @defun Block.is_valid () Returns @code{True} if the @code{gdb.Block} object is valid, @code{False} if not. A block object can become invalid if the block it refers to doesn't exist anymore in the inferior. All other @code{gdb.Block} methods will throw an exception if it is invalid at -the time the method is called. This method is also made available to -the Python iterator object that @code{gdb.Block} provides in an iteration -context and via the Python @code{iter} built-in function. +the time the method is called. The block's validity is also checked +during iteration over symbols of the block. @end defun -@end table A @code{gdb.Block} object has the following attributes: -@table @code @defvar Block.start The start address of the block. This attribute is not writable. @end defvar @@ -23819,7 +25537,6 @@ writable. @code{True} if the @code{gdb.Block} object is a static block, @code{False} if not. This attribute is not writable. @end defvar -@end table @node Symbols In Python @subsubsection Python representation of Symbols. @@ -23875,7 +25592,6 @@ is not found. A @code{gdb.Symbol} object has the following attributes: -@table @code @defvar Symbol.type The type of the symbol or @code{None} if no type is recorded. This attribute is represented as a @code{gdb.Type} object. @@ -23888,6 +25604,11 @@ represented as a @code{gdb.Symtab} object. @xref{Symbol Tables In Python}. This attribute is not writable. @end defvar +@defvar Symbol.line +The line number in the source code at which the symbol was defined. +This is an integer. +@end defvar + @defvar Symbol.name The name of the symbol as a string. This attribute is not writable. @end defvar @@ -23909,6 +25630,12 @@ of a symbol. Each address class is a constant defined in the @code{gdb} module and described later in this chapter. @end defvar +@defvar Symbol.needs_frame +This is @code{True} if evaluating this symbol's value requires a frame +(@pxref{Frames In Python}) and @code{False} otherwise. Typically, +local variables will require a frame, but other symbols will not. +@end defvar + @defvar Symbol.is_argument @code{True} if the symbol is an argument of a function. @end defvar @@ -23924,11 +25651,9 @@ of a symbol. Each address class is a constant defined in the @defvar Symbol.is_variable @code{True} if the symbol is a variable. @end defvar -@end table A @code{gdb.Symbol} object has the following methods: -@table @code @defun Symbol.is_valid () Returns @code{True} if the @code{gdb.Symbol} object is valid, @code{False} if not. A @code{gdb.Symbol} object can become invalid if @@ -23936,7 +25661,15 @@ the symbol it refers to does not exist in @value{GDBN} any longer. All other @code{gdb.Symbol} methods will throw an exception if it is invalid at the time the method is called. @end defun -@end table + +@defun Symbol.value (@r{[}frame@r{]}) +Compute the value of the symbol, as a @code{gdb.Value}. For +functions, this computes the address of the function, cast to the +appropriate type. If the symbol requires a frame in order to compute +its value, then @var{frame} must be given. If @var{frame} is not +given, or if @var{frame} is invalid, then this method will throw an +exception. +@end defun The available domain categories in @code{gdb.Symbol} are represented as constants in the @code{gdb} module: @@ -24065,26 +25798,28 @@ For more information on @value{GDBN}'s symbol table management, see A @code{gdb.Symtab_and_line} object has the following attributes: -@table @code @defvar Symtab_and_line.symtab The symbol table object (@code{gdb.Symtab}) for this frame. This attribute is not writable. @end defvar @defvar Symtab_and_line.pc -Indicates the current program counter address. This attribute is not -writable. +Indicates the start of the address range occupied by code for the +current source line. This attribute is not writable. +@end defvar + +@defvar Symtab_and_line.last +Indicates the end of the address range occupied by code for the current +source line. This attribute is not writable. @end defvar @defvar Symtab_and_line.line Indicates the current line number for this object. This attribute is not writable. @end defvar -@end table A @code{gdb.Symtab_and_line} object has the following methods: -@table @code @defun Symtab_and_line.is_valid () Returns @code{True} if the @code{gdb.Symtab_and_line} object is valid, @code{False} if not. A @code{gdb.Symtab_and_line} object can become @@ -24093,11 +25828,9 @@ exist in @value{GDBN} any longer. All other @code{gdb.Symtab_and_line} methods will throw an exception if it is invalid at the time the method is called. @end defun -@end table A @code{gdb.Symtab} object has the following attributes: -@table @code @defvar Symtab.filename The symbol table's source filename. This attribute is not writable. @end defvar @@ -24106,11 +25839,9 @@ The symbol table's source filename. This attribute is not writable. The symbol table's backing object file. @xref{Objfiles In Python}. This attribute is not writable. @end defvar -@end table A @code{gdb.Symtab} object has the following methods: -@table @code @defun Symtab.is_valid () Returns @code{True} if the @code{gdb.Symtab} object is valid, @code{False} if not. A @code{gdb.Symtab} object can become invalid if @@ -24122,7 +25853,16 @@ if it is invalid at the time the method is called. @defun Symtab.fullname () Return the symbol table's source absolute file name. @end defun -@end table + +@defun Symtab.global_block () +Return the global block of the underlying symbol table. +@xref{Blocks In Python}. +@end defun + +@defun Symtab.static_block () +Return the static block of the underlying symbol table. +@xref{Blocks In Python}. +@end defun @node Breakpoints In Python @subsubsection Manipulating breakpoints using Python @@ -24437,20 +26177,66 @@ resolve this to the lazy string's character type, use the type's writable. @end defvar -@node Auto-loading -@subsection Auto-loading -@cindex auto-loading, Python +@node Architectures In Python +@subsubsection Python representation of architectures +@cindex Python architectures + +@value{GDBN} uses architecture specific parameters and artifacts in a +number of its various computations. An architecture is represented +by an instance of the @code{gdb.Architecture} class. + +A @code{gdb.Architecture} class has the following methods: + +@defun Architecture.name () +Return the name (string value) of the architecture. +@end defun + +@defun Architecture.disassemble (@var{start_pc} @r{[}, @var{end_pc} @r{[}, @var{count}@r{]]}) +Return a list of disassembled instructions starting from the memory +address @var{start_pc}. The optional arguments @var{end_pc} and +@var{count} determine the number of instructions in the returned list. +If both the optional arguments @var{end_pc} and @var{count} are +specified, then a list of at most @var{count} disassembled instructions +whose start address falls in the closed memory address interval from +@var{start_pc} to @var{end_pc} are returned. If @var{end_pc} is not +specified, but @var{count} is specified, then @var{count} number of +instructions starting from the address @var{start_pc} are returned. If +@var{count} is not specified but @var{end_pc} is specified, then all +instructions whose start address falls in the closed memory address +interval from @var{start_pc} to @var{end_pc} are returned. If neither +@var{end_pc} nor @var{count} are specified, then a single instruction at +@var{start_pc} is returned. For all of these cases, each element of the +returned list is a Python @code{dict} with the following string keys: + +@table @code + +@item addr +The value corresponding to this key is a Python long integer capturing +the memory address of the instruction. + +@item asm +The value corresponding to this key is a string value which represents +the instruction with assembly language mnemonics. The assembly +language flavor used is the same as that specified by the current CLI +variable @code{disassembly-flavor}. @xref{Machine Code}. + +@item length +The value corresponding to this key is the length (integer value) of the +instruction in bytes. + +@end table +@end defun + +@node Python Auto-loading +@subsection Python Auto-loading +@cindex Python auto-loading When a new object file is read (for example, due to the @code{file} command, or because the inferior has loaded a shared library), @value{GDBN} will look for Python support scripts in several ways: -@file{@var{objfile}-gdb.py} and @code{.debug_gdb_scripts} section. - -@menu -* objfile-gdb.py file:: The @file{@var{objfile}-gdb.py} file -* .debug_gdb_scripts section:: The @code{.debug_gdb_scripts} section -* Which flavor to choose?:: -@end menu +@file{@var{objfile}-gdb.py} (@pxref{objfile-gdb.py file}) +and @code{.debug_gdb_scripts} section +(@pxref{dotdebug_gdb_scripts section}). The auto-loading feature is useful for supplying application-specific debugging commands and scripts. @@ -24459,36 +26245,39 @@ Auto-loading can be enabled or disabled, and the list of auto-loaded scripts can be printed. @table @code -@kindex set auto-load-scripts -@item set auto-load-scripts [yes|no] +@anchor{set auto-load python-scripts} +@kindex set auto-load python-scripts +@item set auto-load python-scripts [on|off] Enable or disable the auto-loading of Python scripts. -@kindex show auto-load-scripts -@item show auto-load-scripts +@anchor{show auto-load python-scripts} +@kindex show auto-load python-scripts +@item show auto-load python-scripts Show whether auto-loading of Python scripts is enabled or disabled. -@kindex info auto-load-scripts -@cindex print list of auto-loaded scripts -@item info auto-load-scripts [@var{regexp}] -Print the list of all scripts that @value{GDBN} auto-loaded. +@anchor{info auto-load python-scripts} +@kindex info auto-load python-scripts +@cindex print list of auto-loaded Python scripts +@item info auto-load python-scripts [@var{regexp}] +Print the list of all Python scripts that @value{GDBN} auto-loaded. -Also printed is the list of scripts that were mentioned in +Also printed is the list of Python scripts that were mentioned in the @code{.debug_gdb_scripts} section and were not found -(@pxref{.debug_gdb_scripts section}). +(@pxref{dotdebug_gdb_scripts section}). This is useful because their names are not printed when @value{GDBN} tries to load them and fails. There may be many of them, and printing an error message for each one is problematic. -If @var{regexp} is supplied only scripts with matching names are printed. +If @var{regexp} is supplied only Python scripts with matching names are printed. Example: @smallexample -(gdb) info auto-load-scripts -Loaded Script -Yes py-section-script.py - full name: /tmp/py-section-script.py -Missing my-foo-pretty-printers.py +(gdb) info auto-load python-scripts +Loaded Script +Yes py-section-script.py + full name: /tmp/py-section-script.py +No my-foo-pretty-printers.py @end smallexample @end table @@ -24497,27 +26286,69 @@ When reading an auto-loaded file, @value{GDBN} sets the function (@pxref{Objfiles In Python}). This can be useful for registering objfile-specific pretty-printers. +@menu +* objfile-gdb.py file:: The @file{@var{objfile}-gdb.py} file +* dotdebug_gdb_scripts section:: The @code{.debug_gdb_scripts} section +* Which flavor to choose?:: +@end menu + @node objfile-gdb.py file @subsubsection The @file{@var{objfile}-gdb.py} file @cindex @file{@var{objfile}-gdb.py} When a new object file is read, @value{GDBN} looks for -a file named @file{@var{objfile}-gdb.py}, +a file named @file{@var{objfile}-gdb.py} (we call it @var{script-name} below), where @var{objfile} is the object file's real name, formed by ensuring that the file name is absolute, 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 (@pxref{Separate Debug Files}), -then @value{GDBN} will look for @var{real-name} in all of the -directories mentioned in the value of @code{debug-file-directory}. +If this file does not exist, then @value{GDBN} will look for +@var{script-name} file in all of the directories as specified below. -Finally, if this file does not exist, then @value{GDBN} will look for -a file named @file{@var{data-directory}/python/auto-load/@var{real-name}}, where -@var{data-directory} is @value{GDBN}'s data directory (available via -@code{show data-directory}, @pxref{Data Files}), and @var{real-name} -is the object file's real name, as described above. +Note that loading of this script file also requires accordingly configured +@code{auto-load safe-path} (@pxref{Auto-loading safe path}). + +For object files using @file{.exe} suffix @value{GDBN} tries to load first the +scripts normally according to its @file{.exe} filename. But if no scripts are +found @value{GDBN} also tries script filenames matching the object file without +its @file{.exe} suffix. This @file{.exe} stripping is case insensitive and it +is attempted on any platform. This makes the script filenames compatible +between Unix and MS-Windows hosts. + +@table @code +@anchor{set auto-load scripts-directory} +@kindex set auto-load scripts-directory +@item set auto-load scripts-directory @r{[}@var{directories}@r{]} +Control @value{GDBN} auto-loaded scripts location. Multiple directory entries +may be delimited by the host platform path separator in use +(@samp{:} on Unix, @samp{;} on MS-Windows and MS-DOS). + +Each entry here needs to be covered also by the security setting +@code{set auto-load safe-path} (@pxref{set auto-load safe-path}). + +@anchor{with-auto-load-dir} +This variable defaults to @file{$debugdir:$datadir/auto-load}. The default +@code{set auto-load safe-path} value can be also overriden by @value{GDBN} +configuration option @option{--with-auto-load-dir}. + +Any reference to @file{$debugdir} will get replaced by +@var{debug-file-directory} value (@pxref{Separate Debug Files}) and any +reference to @file{$datadir} will get replaced by @var{data-directory} which is +determined at @value{GDBN} startup (@pxref{Data Files}). @file{$debugdir} and +@file{$datadir} must be placed as a directory component --- either alone or +delimited by @file{/} or @file{\} directory separators, depending on the host +platform. + +The list of directories uses path separator (@samp{:} on GNU and Unix +systems, @samp{;} on MS-Windows and MS-DOS) to separate directories, similarly +to the @env{PATH} environment variable. + +@anchor{show auto-load scripts-directory} +@kindex show auto-load scripts-directory +@item show auto-load scripts-directory +Show @value{GDBN} auto-loaded scripts location. +@end table @value{GDBN} does not track which files it has already auto-loaded this way. @value{GDBN} will load the associated script every time the corresponding @@ -24525,7 +26356,7 @@ is the object file's real name, as described above. So your @file{-gdb.py} file should be careful to avoid errors if it is evaluated more than once. -@node .debug_gdb_scripts section +@node dotdebug_gdb_scripts section @subsubsection The @code{.debug_gdb_scripts} section @cindex @code{.debug_gdb_scripts} section @@ -24563,6 +26394,9 @@ DEFINE_GDB_SCRIPT ("my-app-scripts.py") The script name may include directories if desired. +Note that loading of this script file also requires accordingly configured +@code{auto-load safe-path} (@pxref{Auto-loading safe path}). + If the macro is put in a header, any application or library using this header will get a reference to the specified script. @@ -24652,6 +26486,13 @@ Utility class for handling multiple printers, all recognized via regular expressions. @xref{Writing a Pretty-Printer}, for an example. +@item FlagEnumerationPrinter (@var{name}) +A pretty-printer which handles printing of @code{enum} values. Unlike +@value{GDBN}'s built-in @code{enum} printing, this printer attempts to +work properly when there is some overlap between the enumeration +constants. @var{name} is the name of the printer and also the name of +the @code{enum} type to look up. + @item register_pretty_printer (@var{obj}, @var{printer}, @var{replace}=False) Register @var{printer} with the pretty-printer list of @var{obj}. If @var{replace} is @code{True} then any existing copy of the printer @@ -24664,7 +26505,7 @@ if a printer with the same name already exists. @cindex gdb.types This module provides a collection of utilities for working with -@code{gdb.Types} objects. +@code{gdb.Type} objects. @table @code @item get_basic_type (@var{type}) @@ -24725,6 +26566,37 @@ Then in @value{GDBN}: @{['a', 'b0', 'b1']@} @end smallexample +@item get_type_recognizers () +Return a list of the enabled type recognizers for the current context. +This is called by @value{GDBN} during the type-printing process +(@pxref{Type Printing API}). + +@item apply_type_recognizers (recognizers, type_obj) +Apply the type recognizers, @var{recognizers}, to the type object +@var{type_obj}. If any recognizer returns a string, return that +string. Otherwise, return @code{None}. This is called by +@value{GDBN} during the type-printing process (@pxref{Type Printing +API}). + +@item register_type_printer (locus, printer) +This is a convenience function to register a type printer. +@var{printer} is the type printer to register. It must implement the +type printer protocol. @var{locus} is either a @code{gdb.Objfile}, in +which case the printer is registered with that objfile; a +@code{gdb.Progspace}, in which case the printer is registered with +that progspace; or @code{None}, in which case the printer is +registered globally. + +@item TypePrinter +This is a base class that implements the type printer protocol. Type +printers are encouraged, but not required, to derive from this class. +It defines a constructor: + +@defmethod TypePrinter __init__ (self, name) +Initialize the type printer with the given name. The new printer +starts in the enabled state. +@end defmethod + @end table @node gdb.prompt @@ -24955,9 +26827,8 @@ commands in separate text windows. The TUI mode is supported only on platforms where a suitable version of the @code{curses} library is available. -@pindex @value{GDBTUI} The TUI mode is enabled by default when you invoke @value{GDBN} as -either @samp{@value{GDBTUI}} or @samp{@value{GDBP} -tui}. +@samp{@value{GDBP} -tui}. You can also switch in and out of TUI mode while @value{GDBN} runs by using various TUI commands and key bindings, such as @kbd{C-x C-a}. @xref{TUI Keys, ,TUI Key Bindings}. @@ -25505,21 +27376,6 @@ A more detailed description of Emacs' interaction with @value{GDBN} is given in the Emacs manual (@pxref{Debuggers,,, Emacs, The @sc{gnu} Emacs Manual}). -@c The following dropped because Epoch is nonstandard. Reactivate -@c if/when v19 does something similar. ---doc@cygnus.com 19dec1990 -@ignore -@kindex Emacs Epoch environment -@kindex Epoch -@kindex inspect - -Version 18 of @sc{gnu} Emacs has a built-in window system -called the @code{epoch} -environment. Users of this environment can use a new command, -@code{inspect} which performs identically to @code{print} except that -each value is printed in its own window. -@end ignore - - @node GDB/MI @chapter The @sc{gdb/mi} Interface @@ -25577,6 +27433,7 @@ may repeat one or more times. * GDB/MI Simple Examples:: * GDB/MI Command Description Format:: * GDB/MI Breakpoint Commands:: +* GDB/MI Catchpoint Commands:: * GDB/MI Program Context:: * GDB/MI Thread Commands:: * GDB/MI Ada Tasking Commands:: @@ -26090,6 +27947,7 @@ follow development on @email{gdb@@sourceware.org} and * GDB/MI Result Records:: * GDB/MI Stream Records:: * GDB/MI Async Records:: +* GDB/MI Breakpoint Information:: * GDB/MI Frame Information:: * GDB/MI Thread Information:: * GDB/MI Ada Exception Information:: @@ -26220,8 +28078,9 @@ The inferior exited normally. A signal was received by the inferior. @item solib-event The inferior has stopped due to a library being loaded or unloaded. -This can only happen when @code{stop-on-solib-events} (@pxref{Files}) -is set. +This can happen when @code{stop-on-solib-events} (@pxref{Files}) is +set or when a @code{catch load} or @code{catch unload} catchpoint is +in use (@pxref{Set Catchpoints}). @item fork The inferior has forked. This is reported when @code{catch fork} (@pxref{Set Catchpoints}) has been used. @@ -26315,21 +28174,187 @@ thread group in whose context the library was unloaded. If the field is absent, it means the library was unloaded in the context of all present thread groups. +@item =traceframe-changed,num=@var{tfnum},tracepoint=@var{tpnum} +@itemx =traceframe-changed,end +Reports that the trace frame was changed and its new number is +@var{tfnum}. The number of the tracepoint associated with this trace +frame is @var{tpnum}. + +@item =tsv-created,name=@var{name},initial=@var{initial} +Reports that the new trace state variable @var{name} is created with +initial value @var{initial}. + +@item =tsv-deleted,name=@var{name} +@itemx =tsv-deleted +Reports that the trace state variable @var{name} is deleted or all +trace state variables are deleted. + +@item =tsv-modified,name=@var{name},initial=@var{initial}[,current=@var{current}] +Reports that the trace state variable @var{name} is modified with +the initial value @var{initial}. The current value @var{current} of +trace state variable is optional and is reported if the current +value of trace state variable is known. + @item =breakpoint-created,bkpt=@{...@} @itemx =breakpoint-modified,bkpt=@{...@} -@itemx =breakpoint-deleted,bkpt=@{...@} +@itemx =breakpoint-deleted,id=@var{number} Reports that a breakpoint was created, modified, or deleted, respectively. Only user-visible breakpoints are reported to the MI user. The @var{bkpt} argument is of the same form as returned by the various -breakpoint commands; @xref{GDB/MI Breakpoint Commands}. +breakpoint commands; @xref{GDB/MI Breakpoint Commands}. The +@var{number} is the ordinal number of the breakpoint. Note that if a breakpoint is emitted in the result record of a command, then it will not also be emitted in an async record. +@item =record-started,thread-group="@var{id}" +@itemx =record-stopped,thread-group="@var{id}" +Execution log recording was either started or stopped on an +inferior. The @var{id} is the @value{GDBN} identifier of the thread +group corresponding to the affected inferior. + +@item =cmd-param-changed,param=@var{param},value=@var{value} +Reports that a parameter of the command @code{set @var{param}} is +changed to @var{value}. In the multi-word @code{set} command, +the @var{param} is the whole parameter list to @code{set} command. +For example, In command @code{set check type on}, @var{param} +is @code{check type} and @var{value} is @code{on}. + +@item =memory-changed,thread-group=@var{id},addr=@var{addr},len=@var{len}[,type="code"] +Reports that bytes from @var{addr} to @var{data} + @var{len} were +written in an inferior. The @var{id} is the identifier of the +thread group corresponding to the affected inferior. The optional +@code{type="code"} part is reported if the memory written to holds +executable code. +@end table + +@node GDB/MI Breakpoint Information +@subsection @sc{gdb/mi} Breakpoint Information + +When @value{GDBN} reports information about a breakpoint, a +tracepoint, a watchpoint, or a catchpoint, it uses a tuple with the +following fields: + +@table @code +@item number +The breakpoint number. For a breakpoint that represents one location +of a multi-location breakpoint, this will be a dotted pair, like +@samp{1.2}. + +@item type +The type of the breakpoint. For ordinary breakpoints this will be +@samp{breakpoint}, but many values are possible. + +@item catch-type +If the type of the breakpoint is @samp{catchpoint}, then this +indicates the exact type of catchpoint. + +@item disp +This is the breakpoint disposition---either @samp{del}, meaning that +the breakpoint will be deleted at the next stop, or @samp{keep}, +meaning that the breakpoint will not be deleted. + +@item enabled +This indicates whether the breakpoint is enabled, in which case the +value is @samp{y}, or disabled, in which case the value is @samp{n}. +Note that this is not the same as the field @code{enable}. + +@item addr +The address of the breakpoint. This may be a hexidecimal number, +giving the address; or the string @samp{}, for a pending +breakpoint; or the string @samp{}, for a breakpoint with +multiple locations. This field will not be present if no address can +be determined. For example, a watchpoint does not have an address. + +@item func +If known, the function in which the breakpoint appears. +If not known, this field is not present. + +@item filename +The name of the source file which contains this function, if known. +If not known, this field is not present. + +@item fullname +The full file name of the source file which contains this function, if +known. If not known, this field is not present. + +@item line +The line number at which this breakpoint appears, if known. +If not known, this field is not present. + +@item at +If the source file is not known, this field may be provided. If +provided, this holds the address of the breakpoint, possibly followed +by a symbol name. + +@item pending +If this breakpoint is pending, this field is present and holds the +text used to set the breakpoint, as entered by the user. + +@item evaluated-by +Where this breakpoint's condition is evaluated, either @samp{host} or +@samp{target}. + +@item thread +If this is a thread-specific breakpoint, then this identifies the +thread in which the breakpoint can trigger. + +@item task +If this breakpoint is restricted to a particular Ada task, then this +field will hold the task identifier. + +@item cond +If the breakpoint is conditional, this is the condition expression. + +@item ignore +The ignore count of the breakpoint. + +@item enable +The enable count of the breakpoint. + +@item traceframe-usage +FIXME. + +@item static-tracepoint-marker-string-id +For a static tracepoint, the name of the static tracepoint marker. + +@item mask +For a masked watchpoint, this is the mask. + +@item pass +A tracepoint's pass count. + +@item original-location +The location of the breakpoint as originally specified by the user. +This field is optional. + +@item times +The number of times the breakpoint has been hit. + +@item installed +This field is only given for tracepoints. This is either @samp{y}, +meaning that the tracepoint is installed, or @samp{n}, meaning that it +is not. + +@item what +Some extra data, the exact contents of which are type-dependent. + @end table +For example, here is what the output of @code{-break-insert} +(@pxref{GDB/MI Breakpoint Commands}) might be: + +@smallexample +-> -break-insert main +<- ^done,bkpt=@{number="1",type="breakpoint",disp="keep", + enabled="y",addr="0x08048564",func="main",file="myprog.c", + fullname="/home/nickrob/myprog.c",line="68",thread-groups=["i1"], + times="0"@} +<- (gdb) +@end smallexample + @node GDB/MI Frame Information @subsection @sc{gdb/mi} Frame Information @@ -26421,7 +28446,8 @@ information of the breakpoint. -> -break-insert main <- ^done,bkpt=@{number="1",type="breakpoint",disp="keep", enabled="y",addr="0x08048564",func="main",file="myprog.c", - fullname="/home/nickrob/myprog.c",line="68",times="0"@} + fullname="/home/nickrob/myprog.c",line="68",thread-groups=["i1"], + times="0"@} <- (gdb) @end smallexample @@ -26545,7 +28571,8 @@ The corresponding @value{GDBN} command is @samp{ignore}. -break-insert main ^done,bkpt=@{number="1",type="breakpoint",disp="keep", enabled="y",addr="0x000100d0",func="main",file="hello.c", -fullname="/home/foo/hello.c",line="5",times="0"@} +fullname="/home/foo/hello.c",line="5",thread-groups=["i1"], +times="0"@} (gdb) -break-after 1 3 ~ @@ -26561,7 +28588,7 @@ hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@}, @{width="40",alignment="2",col_name="what",colhdr="What"@}], body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y", addr="0x000100d0",func="main",file="hello.c",fullname="/home/foo/hello.c", -line="5",times="0",ignore="3"@}]@} +line="5",thread-groups=["i1"],times="0",ignore="3"@}]@} (gdb) @end smallexample @@ -26597,7 +28624,8 @@ The corresponding @value{GDBN} command is @samp{commands}. -break-insert main ^done,bkpt=@{number="1",type="breakpoint",disp="keep", enabled="y",addr="0x000100d0",func="main",file="hello.c", -fullname="/home/foo/hello.c",line="5",times="0"@} +fullname="/home/foo/hello.c",line="5",thread-groups=["i1"], +times="0"@} (gdb) -break-commands 1 "print v" "continue" ^done @@ -26639,7 +28667,7 @@ hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@}, @{width="40",alignment="2",col_name="what",colhdr="What"@}], body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y", addr="0x000100d0",func="main",file="hello.c",fullname="/home/foo/hello.c", -line="5",cond="1",times="0",ignore="3"@}]@} +line="5",cond="1",thread-groups=["i1"],times="0",ignore="3"@}]@} (gdb) @end smallexample @@ -26711,7 +28739,7 @@ hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@}, @{width="40",alignment="2",col_name="what",colhdr="What"@}], body=[bkpt=@{number="2",type="breakpoint",disp="keep",enabled="n", addr="0x000100d0",func="main",file="hello.c",fullname="/home/foo/hello.c", -line="5",times="0"@}]@} +line="5",thread-groups=["i1"],times="0"@}]@} (gdb) @end smallexample @@ -26747,7 +28775,7 @@ hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@}, @{width="40",alignment="2",col_name="what",colhdr="What"@}], body=[bkpt=@{number="2",type="breakpoint",disp="keep",enabled="y", addr="0x000100d0",func="main",file="hello.c",fullname="/home/foo/hello.c", -line="5",times="0"@}]@} +line="5",thread-groups=["i1"],times="0"@}]@} (gdb) @end smallexample @@ -26763,6 +28791,10 @@ line="5",times="0"@}]@} @c REDUNDANT??? Get information about a single breakpoint. +The result is a table of breakpoints. @xref{GDB/MI Breakpoint +Information}, for details on the format of each breakpoint in the +table. + @subsubheading @value{GDBN} Command The corresponding @value{GDBN} command is @samp{info break @var{breakpoint}}. @@ -26778,7 +28810,7 @@ N.A. @smallexample -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ] [ -c @var{condition} ] [ -i @var{ignore-count} ] - [ -p @var{thread} ] [ @var{location} ] + [ -p @var{thread-id} ] [ @var{location} ] @end smallexample @noindent @@ -26801,10 +28833,6 @@ The possible optional parameters of this command are: Insert a temporary breakpoint. @item -h Insert a hardware breakpoint. -@item -c @var{condition} -Make the breakpoint conditional on @var{condition}. -@item -i @var{ignore-count} -Initialize the @var{ignore-count}. @item -f If @var{location} cannot be parsed (for example if it refers to unknown files or functions), create a pending @@ -26816,27 +28844,18 @@ Create a disabled breakpoint. @item -a Create a tracepoint. @xref{Tracepoints}. When this parameter is used together with @samp{-h}, a fast tracepoint is created. +@item -c @var{condition} +Make the breakpoint conditional on @var{condition}. +@item -i @var{ignore-count} +Initialize the @var{ignore-count}. +@item -p @var{thread-id} +Restrict the breakpoint to the specified @var{thread-id}. @end table @subsubheading Result -The result is in the form: - -@smallexample -^done,bkpt=@{number="@var{number}",type="@var{type}",disp="del"|"keep", -enabled="y"|"n",addr="@var{hex}",func="@var{funcname}",file="@var{filename}", -fullname="@var{full_filename}",line="@var{lineno}",[thread="@var{threadno},] -times="@var{times}"@} -@end smallexample - -@noindent -where @var{number} is the @value{GDBN} number for this breakpoint, -@var{funcname} is the name of the function where the breakpoint was -inserted, @var{filename} is the name of the source file which contains -this function, @var{lineno} is the source line number within that file -and @var{times} the number of times that the breakpoint has been hit -(always 0 for -break-insert but may be greater for -break-info or -break-list -which use the same output). +@xref{GDB/MI Breakpoint Information}, for details on the format of the +resulting breakpoint. Note: this format is open to change. @c An out-of-band breakpoint instead of part of the result? @@ -26844,7 +28863,7 @@ Note: this format is open to change. @subsubheading @value{GDBN} Command The corresponding @value{GDBN} commands are @samp{break}, @samp{tbreak}, -@samp{hbreak}, @samp{thbreak}, and @samp{rbreak}. +@samp{hbreak}, and @samp{thbreak}. @c and @samp{rbreak}. @subsubheading Example @@ -26852,11 +28871,13 @@ The corresponding @value{GDBN} commands are @samp{break}, @samp{tbreak}, (gdb) -break-insert main ^done,bkpt=@{number="1",addr="0x0001072c",file="recursive2.c", -fullname="/home/foo/recursive2.c,line="4",times="0"@} +fullname="/home/foo/recursive2.c,line="4",thread-groups=["i1"], +times="0"@} (gdb) -break-insert -t foo ^done,bkpt=@{number="2",addr="0x00010774",file="recursive2.c", -fullname="/home/foo/recursive2.c,line="11",times="0"@} +fullname="/home/foo/recursive2.c,line="11",thread-groups=["i1"], +times="0"@} (gdb) -break-list ^done,BreakpointTable=@{nr_rows="2",nr_cols="6", @@ -26868,16 +28889,19 @@ hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@}, @{width="40",alignment="2",col_name="what",colhdr="What"@}], body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y", addr="0x0001072c", func="main",file="recursive2.c", -fullname="/home/foo/recursive2.c,"line="4",times="0"@}, +fullname="/home/foo/recursive2.c,"line="4",thread-groups=["i1"], +times="0"@}, bkpt=@{number="2",type="breakpoint",disp="del",enabled="y", addr="0x00010774",func="foo",file="recursive2.c", -fullname="/home/foo/recursive2.c",line="11",times="0"@}]@} -(gdb) --break-insert -r foo.* -~int foo(int, int); -^done,bkpt=@{number="3",addr="0x00010774",file="recursive2.c, -"fullname="/home/foo/recursive2.c",line="11",times="0"@} +fullname="/home/foo/recursive2.c",line="11",thread-groups=["i1"], +times="0"@}]@} (gdb) +@c -break-insert -r foo.* +@c ~int foo(int, int); +@c ^done,bkpt=@{number="3",addr="0x00010774",file="recursive2.c, +@c "fullname="/home/foo/recursive2.c",line="11",thread-groups=["i1"], +@c times="0"@} +@c (gdb) @end smallexample @subheading The @code{-break-list} Command @@ -26906,6 +28930,8 @@ memory location at which the breakpoint is set @item What logical location of the breakpoint, expressed by function name, file name, line number +@item Thread-groups +list of thread groups to which this breakpoint applies @item Times number of times the breakpoint has been hit @end table @@ -26930,10 +28956,11 @@ hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@}, @{width="10",alignment="-1",col_name="addr",colhdr="Address"@}, @{width="40",alignment="2",col_name="what",colhdr="What"@}], body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y", -addr="0x000100d0",func="main",file="hello.c",line="5",times="0"@}, +addr="0x000100d0",func="main",file="hello.c",line="5",thread-groups=["i1"], +times="0"@}, bkpt=@{number="2",type="breakpoint",disp="keep",enabled="y", addr="0x00010114",func="foo",file="hello.c",fullname="/home/foo/hello.c", -line="13",times="0"@}]@} +line="13",thread-groups=["i1"],times="0"@}]@} (gdb) @end smallexample @@ -27061,9 +29088,10 @@ hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@}, body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y", addr="0x00010734",func="callee4", file="../../../devo/gdb/testsuite/gdb.mi/basics.c", -fullname="/home/foo/devo/gdb/testsuite/gdb.mi/basics.c"line="8",times="1"@}, +fullname="/home/foo/devo/gdb/testsuite/gdb.mi/basics.c"line="8",thread-groups=["i1"], +times="1"@}, bkpt=@{number="2",type="watchpoint",disp="keep", -enabled="y",addr="",what="C",times="0"@}]@} +enabled="y",addr="",what="C",thread-groups=["i1"],times="0"@}]@} (gdb) -exec-continue ^running @@ -27085,9 +29113,10 @@ hdr=[@{width="3",alignment="-1",col_name="number",colhdr="Num"@}, body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y", addr="0x00010734",func="callee4", file="../../../devo/gdb/testsuite/gdb.mi/basics.c", -fullname="/home/foo/devo/gdb/testsuite/gdb.mi/basics.c",line="8",times="1"@}, +fullname="/home/foo/devo/gdb/testsuite/gdb.mi/basics.c",line="8",thread-groups=["i1"], +times="1"@}, bkpt=@{number="2",type="watchpoint",disp="keep", -enabled="y",addr="",what="C",times="-5"@}]@} +enabled="y",addr="",what="C",thread-groups=["i1"],times="-5"@}]@} (gdb) -exec-continue ^running @@ -27109,10 +29138,77 @@ body=[bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y", addr="0x00010734",func="callee4", file="../../../devo/gdb/testsuite/gdb.mi/basics.c", fullname="/home/foo/devo/gdb/testsuite/gdb.mi/basics.c",line="8", -times="1"@}]@} +thread-groups=["i1"],times="1"@}]@} +(gdb) +@end smallexample + + +@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@node GDB/MI Catchpoint Commands +@section @sc{gdb/mi} Catchpoint Commands + +This section documents @sc{gdb/mi} commands for manipulating +catchpoints. + +@subheading The @code{-catch-load} Command +@findex -catch-load + +@subsubheading Synopsis + +@smallexample + -catch-load [ -t ] [ -d ] @var{regexp} +@end smallexample + +Add a catchpoint for library load events. If the @samp{-t} option is used, +the catchpoint is a temporary one (@pxref{Set Breaks, ,Setting +Breakpoints}). If the @samp{-d} option is used, the catchpoint is created +in a disabled state. The @samp{regexp} argument is a regular +expression used to match the name of the loaded library. + + +@subsubheading @value{GDBN} Command + +The corresponding @value{GDBN} command is @samp{catch load}. + +@subsubheading Example + +@smallexample +-catch-load -t foo.so +^done,bkpt=@{number="1",type="catchpoint",disp="del",enabled="y", +what="load of library matching foo.so",catch-type="load",times="0"@} +(gdb) +@end smallexample + + +@subheading The @code{-catch-unload} Command +@findex -catch-unload + +@subsubheading Synopsis + +@smallexample + -catch-unload [ -t ] [ -d ] @var{regexp} +@end smallexample + +Add a catchpoint for library unload events. If the @samp{-t} option is +used, the catchpoint is a temporary one (@pxref{Set Breaks, ,Setting +Breakpoints}). If the @samp{-d} option is used, the catchpoint is +created in a disabled state. The @samp{regexp} argument is a regular +expression used to match the name of the unloaded library. + +@subsubheading @value{GDBN} Command + +The corresponding @value{GDBN} command is @samp{catch unload}. + +@subsubheading Example + +@smallexample +-catch-unload -d bar.so +^done,bkpt=@{number="2",type="catchpoint",disp="keep",enabled="n", +what="load of library matching bar.so",catch-type="unload",times="0"@} (gdb) @end smallexample + @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @node GDB/MI Program Context @section @sc{gdb/mi} Program Context @@ -28677,7 +30773,10 @@ will not be interesting. @item type The varobj's type. This is a string representation of the type, as -would be printed by the @value{GDBN} CLI. +would be printed by the @value{GDBN} CLI. If @samp{print object} +(@pxref{Print Settings, set print object}) is set to @code{on}, the +@emph{actual} (derived) type of the object is shown rather than the +@emph{declared} one. @item thread-id If a variable object is bound to a specific thread, then this is the @@ -28848,7 +30947,10 @@ Number of children this child has. For a dynamic varobj, this will be 0. @item type -The type of the child. +The type of the child. If @samp{print object} +(@pxref{Print Settings, set print object}) is set to @code{on}, the +@emph{actual} (derived) type of the object is shown rather than the +@emph{declared} one. @item value If values were requested, this is the value. @@ -29103,6 +31205,12 @@ This is only present if the varobj is still valid. If the type changed, then this will be the string @samp{true}; otherwise it will be @samp{false}. +When a varobj's type changes, its children are also likely to have +become incorrect. Therefore, the varobj's children are automatically +deleted when this attribute is @samp{true}. Also, the varobj's update +range, when set using the @code{-var-set-update-range} command, is +unset. + @item new_type If the varobj's type changed, then this field will be present and will hold the new type. @@ -29327,21 +31435,69 @@ mixed source and disassembly with raw opcodes). @subsubheading Result -The output for each instruction is composed of four fields: +The result of the @code{-data-disassemble} command will be a list named +@samp{asm_insns}, the contents of this list depend on the @var{mode} +used with the @code{-data-disassemble} command. -@itemize @bullet -@item Address -@item Func-name -@item Offset -@item Instruction -@end itemize +For modes 0 and 2 the @samp{asm_insns} list contains tuples with the +following fields: + +@table @code +@item address +The address at which this instruction was disassembled. + +@item func-name +The name of the function this instruction is within. + +@item offset +The decimal offset in bytes from the start of @samp{func-name}. + +@item inst +The text disassembly for this @samp{address}. + +@item opcodes +This field is only present for mode 2. This contains the raw opcode +bytes for the @samp{inst} field. + +@end table + +For modes 1 and 3 the @samp{asm_insns} list contains tuples named +@samp{src_and_asm_line}, each of which has the following fields: + +@table @code +@item line +The line number within @samp{file}. + +@item file +The file name from the compilation unit. This might be an absolute +file name or a relative file name depending on the compile command +used. + +@item fullname +Absolute file name of @samp{file}. It is converted to a canonical form +using the source file search path +(@pxref{Source Path, ,Specifying Source Directories}) +and after resolving all the symbolic links. -Note that whatever included in the instruction field, is not manipulated -directly by @sc{gdb/mi}, i.e., it is not possible to adjust its format. +If the source file is not found this field will contain the path as +present in the debug information. + +@item line_asm_insn +This is a list of tuples containing the disassembly for @samp{line} in +@samp{file}. The fields of each tuple are the same as for +@code{-data-disassemble} in @var{mode} 0 and 2, so @samp{address}, +@samp{func-name}, @samp{offset}, @samp{inst}, and optionally +@samp{opcodes}. + +@end table + +Note that whatever included in the @samp{inst} field, is not +manipulated directly by @sc{gdb/mi}, i.e., it is not possible to +adjust its format. @subsubheading @value{GDBN} Command -There's no direct mapping from this command to the CLI. +The corresponding @value{GDBN} command is @samp{disassemble}. @subsubheading Example @@ -29405,15 +31561,15 @@ Disassemble 3 instructions from the start of @code{main} in mixed mode: -data-disassemble -f basics.c -l 32 -n 3 -- 1 ^done,asm_insns=[ src_and_asm_line=@{line="31", -file="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb/ \ - testsuite/gdb.mi/basics.c",line_asm_insn=[ -@{address="0x000107bc",func-name="main",offset="0", -inst="save %sp, -112, %sp"@}]@}, +file="../../../src/gdb/testsuite/gdb.mi/basics.c", +fullname="/absolute/path/to/src/gdb/testsuite/gdb.mi/basics.c", +line_asm_insn=[@{address="0x000107bc", +func-name="main",offset="0",inst="save %sp, -112, %sp"@}]@}, src_and_asm_line=@{line="32", -file="/kwikemart/marge/ezannoni/flathead-dev/devo/gdb/ \ - testsuite/gdb.mi/basics.c",line_asm_insn=[ -@{address="0x000107c0",func-name="main",offset="4", -inst="mov 2, %o0"@}, +file="../../../src/gdb/testsuite/gdb.mi/basics.c", +fullname="/absolute/path/to/src/gdb/testsuite/gdb.mi/basics.c", +line_asm_insn=[@{address="0x000107c0", +func-name="main",offset="4",inst="mov 2, %o0"@}, @{address="0x000107c4",func-name="main",offset="8", inst="sethi %hi(0x11800), %o2"@}]@}] (gdb) @@ -29837,6 +31993,7 @@ The corresponding @value{GDBN} command is @samp{x}. @smallexample -data-write-memory-bytes @var{address} @var{contents} + -data-write-memory-bytes @var{address} @var{contents} @r{[}@var{count}@r{]} @end smallexample @noindent @@ -29851,6 +32008,11 @@ quoted using the C convention. @item @var{contents} The hex-encoded bytes to write. +@item @var{count} +Optional argument indicating the number of bytes to be written. If @var{count} +is greater than @var{contents}' length, @value{GDBN} will repeatedly +write @var{contents} until it fills @var{count} bytes. + @end table @subsubheading @value{GDBN} Command @@ -29866,6 +32028,12 @@ There's no corresponding @value{GDBN} command. (gdb) @end smallexample +@smallexample +(gdb) +-data-write-memory-bytes &a "aabbccdd" 16e +^done +(gdb) +@end smallexample @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @node GDB/MI Tracepoint Commands @@ -30113,6 +32281,10 @@ The value of the disconnected tracing flag. @code{1} means that tracing will continue after @value{GDBN} disconnects, @code{0} means that the trace run will stop. +@item trace-file +The filename of the trace file being examined. This field is +optional, and only present when examining a trace file. + @end table @subsubheading @value{GDBN} Command @@ -30493,8 +32665,8 @@ The @value{GDBN} equivalent is @samp{info source} List the source files for the current executable. -It will always output the filename, but only when @value{GDBN} can find -the absolute file name of a source file, will it output the fullname. +It will always output both the filename and fullname (absolute file +name) of a source file. @subsubheading @value{GDBN} Command @@ -31363,6 +33535,78 @@ and only if there is a corresponding executable file. @{id="2",target-id="Thread 0xb7e14b90",cores=[2]@}]@},...] @end smallexample +@subheading The @code{-info-os} Command +@findex -info-os + +@subsubheading Synopsis + +@smallexample +-info-os [ @var{type} ] +@end smallexample + +If no argument is supplied, the command returns a table of available +operating-system-specific information types. If one of these types is +supplied as an argument @var{type}, then the command returns a table +of data of that type. + +The types of information available depend on the target operating +system. + +@subsubheading @value{GDBN} Command + +The corresponding @value{GDBN} command is @samp{info os}. + +@subsubheading Example + +When run on a @sc{gnu}/Linux system, the output will look something +like this: + +@smallexample +@value{GDBP} +-info-os +^done,OSDataTable=@{nr_rows="9",nr_cols="3", +hdr=[@{width="10",alignment="-1",col_name="col0",colhdr="Type"@}, + @{width="10",alignment="-1",col_name="col1",colhdr="Description"@}, + @{width="10",alignment="-1",col_name="col2",colhdr="Title"@}], +body=[item=@{col0="processes",col1="Listing of all processes", + col2="Processes"@}, + item=@{col0="procgroups",col1="Listing of all process groups", + col2="Process groups"@}, + item=@{col0="threads",col1="Listing of all threads", + col2="Threads"@}, + item=@{col0="files",col1="Listing of all file descriptors", + col2="File descriptors"@}, + item=@{col0="sockets",col1="Listing of all internet-domain sockets", + col2="Sockets"@}, + item=@{col0="shm",col1="Listing of all shared-memory regions", + col2="Shared-memory regions"@}, + item=@{col0="semaphores",col1="Listing of all semaphores", + col2="Semaphores"@}, + item=@{col0="msg",col1="Listing of all message queues", + col2="Message queues"@}, + item=@{col0="modules",col1="Listing of all loaded kernel modules", + col2="Kernel modules"@}]@} +@value{GDBP} +-info-os processes +^done,OSDataTable=@{nr_rows="190",nr_cols="4", +hdr=[@{width="10",alignment="-1",col_name="col0",colhdr="pid"@}, + @{width="10",alignment="-1",col_name="col1",colhdr="user"@}, + @{width="10",alignment="-1",col_name="col2",colhdr="command"@}, + @{width="10",alignment="-1",col_name="col3",colhdr="cores"@}], +body=[item=@{col0="1",col1="root",col2="/sbin/init",col3="0"@}, + item=@{col0="2",col1="root",col2="[kthreadd]",col3="1"@}, + item=@{col0="3",col1="root",col2="[ksoftirqd/0]",col3="0"@}, + ... + item=@{col0="26446",col1="stan",col2="bash",col3="0"@}, + item=@{col0="28152",col1="stan",col2="bash",col3="1"@}]@} +(gdb) +@end smallexample + +(Note that the MI output here includes a @code{"Title"} column that +does not appear in command-line @code{info os}; this column is useful +for MI clients that want to enumerate the types of data, such as in a +popup menu, but is needless clutter on the command line, and +@code{info os} omits it.) @subheading The @code{-add-inferior} Command @findex -add-inferior @@ -31495,7 +33739,8 @@ No equivalent. -break-insert main ^done,bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y", addr="0x080484ed",func="main",file="myprog.c", -fullname="/home/nickrob/myprog.c",line="73",times="0"@}, +fullname="/home/nickrob/myprog.c",line="73",thread-groups=["i1"], +times="0"@}, time=@{wallclock="0.05185",user="0.00800",system="0.00000"@} (gdb) -enable-timings no @@ -32008,15 +34253,19 @@ Readers can be loaded and unloaded using the @code{jit-reader-load} and @code{jit-reader-unload} commands. @table @code -@item jit-reader-load @var{reader-name} -Load the JIT reader named @var{reader-name}. On a UNIX system, this -will usually load @file{@var{libdir}/gdb/@var{reader-name}}, where -@var{libdir} is the system library directory, usually -@file{/usr/local/lib}. Only one reader can be active at a time; -trying to load a second reader when one is already loaded will result -in @value{GDBN} reporting an error. A new JIT reader can be loaded by -first unloading the current one using @code{jit-reader-load} and then -invoking @code{jit-reader-load}. +@item jit-reader-load @var{reader} +Load the JIT reader named @var{reader}. @var{reader} is a shared +object specified as either an absolute or a relative file name. In +the latter case, @value{GDBN} will try to load the reader from a +pre-configured directory, usually @file{@var{libdir}/gdb/} on a UNIX +system (here @var{libdir} is the system library directory, often +@file{/usr/local/lib}). + +Only one reader can be active at a time; trying to load a second +reader when one is already loaded will result in @value{GDBN} +reporting an error. A new JIT reader can be loaded by first unloading +the current one using @code{jit-reader-unload} and then invoking +@code{jit-reader-load}. @item jit-reader-unload Unload the currently loaded JIT reader. @@ -32086,6 +34335,219 @@ frame and to write out the values of the registers in the previous frame. Both have a callback (@code{target_read}) to read bytes off the target's address space. +@node In-Process Agent +@chapter In-Process Agent +@cindex debugging agent +The traditional debugging model is conceptually low-speed, but works fine, +because most bugs can be reproduced in debugging-mode execution. However, +as multi-core or many-core processors are becoming mainstream, and +multi-threaded programs become more and more popular, there should be more +and more bugs that only manifest themselves at normal-mode execution, for +example, thread races, because debugger's interference with the program's +timing may conceal the bugs. On the other hand, in some applications, +it is not feasible for the debugger to interrupt the program's execution +long enough for the developer to learn anything helpful about its behavior. +If the program's correctness depends on its real-time behavior, delays +introduced by a debugger might cause the program to fail, even when the +code itself is correct. It is useful to be able to observe the program's +behavior without interrupting it. + +Therefore, traditional debugging model is too intrusive to reproduce +some bugs. In order to reduce the interference with the program, we can +reduce the number of operations performed by debugger. The +@dfn{In-Process Agent}, a shared library, is running within the same +process with inferior, and is able to perform some debugging operations +itself. As a result, debugger is only involved when necessary, and +performance of debugging can be improved accordingly. Note that +interference with program can be reduced but can't be removed completely, +because the in-process agent will still stop or slow down the program. + +The in-process agent can interpret and execute Agent Expressions +(@pxref{Agent Expressions}) during performing debugging operations. The +agent expressions can be used for different purposes, such as collecting +data in tracepoints, and condition evaluation in breakpoints. + +@anchor{Control Agent} +You can control whether the in-process agent is used as an aid for +debugging with the following commands: + +@table @code +@kindex set agent on +@item set agent on +Causes the in-process agent to perform some operations on behalf of the +debugger. Just which operations requested by the user will be done +by the in-process agent depends on the its capabilities. For example, +if you request to evaluate breakpoint conditions in the in-process agent, +and the in-process agent has such capability as well, then breakpoint +conditions will be evaluated in the in-process agent. + +@kindex set agent off +@item set agent off +Disables execution of debugging operations by the in-process agent. All +of the operations will be performed by @value{GDBN}. + +@kindex show agent +@item show agent +Display the current setting of execution of debugging operations by +the in-process agent. +@end table + +@menu +* In-Process Agent Protocol:: +@end menu + +@node In-Process Agent Protocol +@section In-Process Agent Protocol +@cindex in-process agent protocol + +The in-process agent is able to communicate with both @value{GDBN} and +GDBserver (@pxref{In-Process Agent}). This section documents the protocol +used for communications between @value{GDBN} or GDBserver and the IPA. +In general, @value{GDBN} or GDBserver sends commands +(@pxref{IPA Protocol Commands}) and data to in-process agent, and then +in-process agent replies back with the return result of the command, or +some other information. The data sent to in-process agent is composed +of primitive data types, such as 4-byte or 8-byte type, and composite +types, which are called objects (@pxref{IPA Protocol Objects}). + +@menu +* IPA Protocol Objects:: +* IPA Protocol Commands:: +@end menu + +@node IPA Protocol Objects +@subsection IPA Protocol Objects +@cindex ipa protocol objects + +The commands sent to and results received from agent may contain some +complex data types called @dfn{objects}. + +The in-process agent is running on the same machine with @value{GDBN} +or GDBserver, so it doesn't have to handle as much differences between +two ends as remote protocol (@pxref{Remote Protocol}) tries to handle. +However, there are still some differences of two ends in two processes: + +@enumerate +@item +word size. On some 64-bit machines, @value{GDBN} or GDBserver can be +compiled as a 64-bit executable, while in-process agent is a 32-bit one. +@item +ABI. Some machines may have multiple types of ABI, @value{GDBN} or +GDBserver is compiled with one, and in-process agent is compiled with +the other one. +@end enumerate + +Here are the IPA Protocol Objects: + +@enumerate +@item +agent expression object. It represents an agent expression +(@pxref{Agent Expressions}). +@anchor{agent expression object} +@item +tracepoint action object. It represents a tracepoint action +(@pxref{Tracepoint Actions,,Tracepoint Action Lists}) to collect registers, +memory, static trace data and to evaluate expression. +@anchor{tracepoint action object} +@item +tracepoint object. It represents a tracepoint (@pxref{Tracepoints}). +@anchor{tracepoint object} + +@end enumerate + +The following table describes important attributes of each IPA protocol +object: + +@multitable @columnfractions .30 .20 .50 +@headitem Name @tab Size @tab Description +@item @emph{agent expression object} @tab @tab +@item length @tab 4 @tab length of bytes code +@item byte code @tab @var{length} @tab contents of byte code +@item @emph{tracepoint action for collecting memory} @tab @tab +@item 'M' @tab 1 @tab type of tracepoint action +@item addr @tab 8 @tab if @var{basereg} is @samp{-1}, @var{addr} is the +address of the lowest byte to collect, otherwise @var{addr} is the offset +of @var{basereg} for memory collecting. +@item len @tab 8 @tab length of memory for collecting +@item basereg @tab 4 @tab the register number containing the starting +memory address for collecting. +@item @emph{tracepoint action for collecting registers} @tab @tab +@item 'R' @tab 1 @tab type of tracepoint action +@item @emph{tracepoint action for collecting static trace data} @tab @tab +@item 'L' @tab 1 @tab type of tracepoint action +@item @emph{tracepoint action for expression evaluation} @tab @tab +@item 'X' @tab 1 @tab type of tracepoint action +@item agent expression @tab length of @tab @ref{agent expression object} +@item @emph{tracepoint object} @tab @tab +@item number @tab 4 @tab number of tracepoint +@item address @tab 8 @tab address of tracepoint inserted on +@item type @tab 4 @tab type of tracepoint +@item enabled @tab 1 @tab enable or disable of tracepoint +@item step_count @tab 8 @tab step +@item pass_count @tab 8 @tab pass +@item numactions @tab 4 @tab number of tracepoint actions +@item hit count @tab 8 @tab hit count +@item trace frame usage @tab 8 @tab trace frame usage +@item compiled_cond @tab 8 @tab compiled condition +@item orig_size @tab 8 @tab orig size +@item condition @tab 4 if condition is NULL otherwise length of +@ref{agent expression object} +@tab zero if condition is NULL, otherwise is +@ref{agent expression object} +@item actions @tab variable +@tab numactions number of @ref{tracepoint action object} +@end multitable + +@node IPA Protocol Commands +@subsection IPA Protocol Commands +@cindex ipa protocol commands + +The spaces in each command are delimiters to ease reading this commands +specification. They don't exist in real commands. + +@table @samp + +@item FastTrace:@var{tracepoint_object} @var{gdb_jump_pad_head} +Installs a new fast tracepoint described by @var{tracepoint_object} +(@pxref{tracepoint object}). @var{gdb_jump_pad_head}, 8-byte long, is the +head of @dfn{jumppad}, which is used to jump to data collection routine +in IPA finally. + +Replies: +@table @samp +@item OK @var{target_address} @var{gdb_jump_pad_head} @var{fjump_size} @var{fjump} +@var{target_address} is address of tracepoint in the inferior. +@var{gdb_jump_pad_head} is updated head of jumppad. Both of +@var{target_address} and @var{gdb_jump_pad_head} are 8-byte long. +@var{fjump} contains a sequence of instructions jump to jumppad entry. +@var{fjump_size}, 4-byte long, is the size of @var{fjump}. +@item E @var{NN} +for an error + +@end table + +@item close +Closes the in-process agent. This command is sent when @value{GDBN} or GDBserver +is about to kill inferiors. + +@item qTfSTM +@xref{qTfSTM}. +@item qTsSTM +@xref{qTsSTM}. +@item qTSTMat +@xref{qTSTMat}. +@item probe_marker_at:@var{address} +Asks in-process agent to probe the marker at @var{address}. + +Replies: +@table @samp +@item E @var{NN} +for an error +@end table +@item unprobe_marker_at:@var{address} +Asks in-process agent to unprobe the marker at @var{address}. +@end table + @node GDB Bugs @chapter Reporting Bugs in @value{GDBN} @cindex bugs in @value{GDBN} @@ -32500,6 +34962,8 @@ or alternatively @pxref{Library List Format for SVR4 Targets}) MS-Windows shared libraries (@pxref{Shared Libraries}) @item Traceframe info (@pxref{Traceframe Info Format}) +@item +Branch trace (@pxref{Branch Trace Format}) @end itemize @item zlib @@ -32862,6 +35326,17 @@ then @value{GDBN} will always look for @file{/usr/share/gdb/gdbinit}, wherever @value{GDBN} is installed. @end itemize +If the configured location of the system-wide init file (as given by the +@option{--with-system-gdbinit} option at configure time) is in the +data-directory (as specified by @option{--with-gdb-datadir} at configure +time) or in one of its subdirectories, then @value{GDBN} will look for the +system-wide init file in the directory specified by the +@option{--data-directory} command-line option. +Note that the system-wide init file is only read once, during @value{GDBN} +initialization. If the data-directory is changed after @value{GDBN} has +started with the @code{set data-directory} command, the file will not be +reread. + @node Maintenance Commands @appendix Maintenance Commands @cindex maintenance commands @@ -32876,8 +35351,8 @@ messages, see @ref{Debugging Output}.) @table @code @kindex maint agent @kindex maint agent-eval -@item maint agent @var{expression} -@itemx maint agent-eval @var{expression} +@item maint agent @r{[}-at @var{location}@r{,}@r{]} @var{expression} +@itemx maint agent-eval @r{[}-at @var{location}@r{,}@r{]} @var{expression} Translate the given @var{expression} into remote agent bytecodes. This command is useful for debugging the Agent Expression mechanism (@pxref{Agent Expressions}). The @samp{agent} version produces an @@ -32888,6 +35363,15 @@ globb} will include bytecodes to record four bytes of memory at each of the addresses of @code{globa} and @code{globb}, while discarding the result of the addition, while an evaluation expression will do the addition and return the sum. +If @code{-at} is given, generate remote agent bytecode for @var{location}. +If not, generate remote agent bytecode for current frame PC address. + +@kindex maint agent-printf +@item maint agent-printf @var{format},@var{expr},... +Translate the given format string and list of argument expressions +into remote agent bytecodes and display them as a disassembled list. +This command is useful for debugging the agent version of dynamic +printf (@pxref{Dynamic Printf}. @kindex maint info breakpoints @item @anchor{maint info breakpoints}maint info breakpoints @@ -32922,6 +35406,11 @@ Shared library events. @end table +@kindex maint info bfds +@item maint info bfds +This prints information about each @code{bfd} object that is known to +@value{GDBN}. @xref{Top, , BFD, bfd, The Binary File Descriptor Library}. + @kindex set displaced-stepping @kindex show displaced-stepping @cindex displaced stepping support @@ -33141,7 +35630,7 @@ If @var{regexp} is specified, only print scripts loaded by object files matching @var{regexp}. For each script, this command prints its name as specified in the objfile, and the full path if known. -@xref{.debug_gdb_scripts section}. +@xref{dotdebug_gdb_scripts section}. @kindex maint print statistics @cindex bcache statistics @@ -33336,6 +35825,7 @@ Show the current setting of the target wait timeout. * Memory Map Format:: * Thread List Format:: * Traceframe Info Format:: +* Branch Trace Format:: @end menu @node Overview @@ -33808,7 +36298,7 @@ Reply: the register's value @item E @var{NN} for an error -@item +@item @w{} Indicating an unrecognized @var{query}. @end table @@ -33960,6 +36450,12 @@ the corresponding stop reply should indicate that the thread has stopped with signal @samp{0}, regardless of whether the target uses some other signal as an implementation detail. +The stub must support @samp{vCont} if it reports support for +multiprocess extensions (@pxref{multiprocess extensions}). Note that in +this case @samp{vCont} actions can be specified to apply to all threads +in a process by using the @samp{p@var{pid}.-1} form of the +@var{thread-id}. + Reply: @xref{Stop Reply Packets}, for the reply specifications. @@ -33972,7 +36468,7 @@ Reply: @item vCont@r{[};@var{action}@dots{}@r{]} The @samp{vCont} packet is supported. Each @var{action} is a supported command in the @samp{vCont} packet. -@item +@item @w{} The @samp{vCont} packet is not supported. @end table @@ -33992,12 +36488,6 @@ together, and sends a @samp{vFlashDone} request after each group; the stub is allowed to delay erase operation until the @samp{vFlashDone} packet is received. -The stub must support @samp{vCont} if it reports support for -multiprocess extensions (@pxref{multiprocess extensions}). Note that in -this case @samp{vCont} actions can be specified to apply to all threads -in a process by using the @samp{p@var{pid}.-1} form of the -@var{thread-id}. - Reply: @table @samp @item OK @@ -34075,19 +36565,8 @@ for success (@pxref{Stop Reply Packets}) @end table @item vStopped -@anchor{vStopped packet} @cindex @samp{vStopped} packet - -In non-stop mode (@pxref{Remote Non-Stop}), acknowledge a previous stop -reply and prompt for the stub to report another one. - -Reply: -@table @samp -@item @r{Any stop packet} -if there is another unreported stop event (@pxref{Stop Reply Packets}) -@item OK -if there are no unreported stop events -@end table +@xref{Notification Packets}. @item X @var{addr},@var{length}:@var{XX@dots{}} @anchor{X packet} @@ -34123,7 +36602,7 @@ avoid potential problems with duplicate packets, the operations should be implemented in an idempotent way.} @item z0,@var{addr},@var{kind} -@itemx Z0,@var{addr},@var{kind} +@itemx Z0,@var{addr},@var{kind}@r{[};@var{cond_list}@dots{}@r{]}@r{[};cmds:@var{persist},@var{cmd_list}@dots{}@r{]} @cindex @samp{z0} packet @cindex @samp{Z0} packet Insert (@samp{Z0}) or remove (@samp{z0}) a memory breakpoint at address @@ -34135,6 +36614,38 @@ A memory breakpoint is implemented by replacing the instruction at the breakpoint in bytes that should be inserted. E.g., the @sc{arm} and @sc{mips} can insert either a 2 or 4 byte breakpoint. Some architectures have additional meanings for @var{kind}; +@var{cond_list} is an optional list of conditional expressions in bytecode +form that should be evaluated on the target's side. These are the +conditions that should be taken into consideration when deciding if +the breakpoint trigger should be reported back to @var{GDBN}. + +The @var{cond_list} parameter is comprised of a series of expressions, +concatenated without separators. Each expression has the following form: + +@table @samp + +@item X @var{len},@var{expr} +@var{len} is the length of the bytecode expression and @var{expr} is the +actual conditional expression in bytecode form. + +@end table + +The optional @var{cmd_list} parameter introduces commands that may be +run on the target, rather than being reported back to @value{GDBN}. +The parameter starts with a numeric flag @var{persist}; if the flag is +nonzero, then the breakpoint may remain active and the commands +continue to be run even when @value{GDBN} disconnects from the target. +Following this flag is a series of expressions concatenated with no +separators. Each expression has the following form: + +@table @samp + +@item X @var{len},@var{expr} +@var{len} is the length of the bytecode expression and @var{expr} is the +actual conditional expression in bytecode form. + +@end table + see @ref{Architecture-Specific Protocol Details}. @emph{Implementation note: It is possible for a target to copy or move @@ -34146,14 +36657,14 @@ Reply: @table @samp @item OK success -@item +@item @w{} not supported @item E @var{NN} for an error @end table @item z1,@var{addr},@var{kind} -@itemx Z1,@var{addr},@var{kind} +@itemx Z1,@var{addr},@var{kind}@r{[};@var{cond_list}@dots{}@r{]} @cindex @samp{z1} packet @cindex @samp{Z1} packet Insert (@samp{Z1}) or remove (@samp{z1}) a hardware breakpoint at @@ -34161,7 +36672,7 @@ address @var{addr}. A hardware breakpoint is implemented using a mechanism that is not dependant on being able to modify the target's memory. @var{kind} -has the same meaning as in @samp{Z0} packets. +and @var{cond_list} have the same meaning as in @samp{Z0} packets. @emph{Implementation note: A hardware breakpoint is not affected by code movement.} @@ -34170,7 +36681,7 @@ Reply: @table @samp @item OK success -@item +@item @w{} not supported @item E @var{NN} for an error @@ -34187,7 +36698,7 @@ Reply: @table @samp @item OK success -@item +@item @w{} not supported @item E @var{NN} for an error @@ -34204,7 +36715,7 @@ Reply: @table @samp @item OK success -@item +@item @w{} not supported @item E @var{NN} for an error @@ -34221,7 +36732,7 @@ Reply: @table @samp @item OK success -@item +@item @w{} not supported @item E @var{NN} for an error @@ -34407,6 +36918,11 @@ Here are the currently defined query and set packets: @table @samp +@item QAgent:1 +@itemx QAgent:0 +Turn on or off the agent as a helper to perform some debugging operations +delegated from @value{GDBN} (@pxref{Control Agent}). + @item QAllow:@var{op}:@var{val}@dots{} @cindex @samp{QAllow} packet Specify which operations @value{GDBN} expects to request of the @@ -34478,7 +36994,7 @@ The request succeeded. @item E @var{nn} An error occurred. @var{nn} are hex digits. -@item +@item @w{} An empty reply indicates that @samp{QDisableRandomization} is not supported by the stub. @end table @@ -34549,7 +37065,7 @@ local storage requested. @item E @var{nn} An error occurred. @var{nn} are hex digits. -@item +@item @w{} An empty reply indicates that @samp{qGetTLSAddr} is not supported by the stub. @end table @@ -34570,7 +37086,7 @@ thread information block. An error occured. This means that either the thread was not found, or the address could not be retrieved. -@item +@item @w{} An empty reply indicates that @samp{qGetTIBAddr} is not supported by the stub. @end table @@ -34638,7 +37154,7 @@ Don't use this packet; use the @samp{qThreadExtraInfo} query instead Reply: see @code{remote.c:remote_unpack_thread_info_response()}. @item QNonStop:1 -@item QNonStop:0 +@itemx QNonStop:0 @cindex non-stop mode, remote request @cindex @samp{QNonStop} packet @anchor{QNonStop} @@ -34653,7 +37169,7 @@ The request succeeded. @item E @var{nn} An error occurred. @var{nn} are hex digits. -@item +@item @w{} An empty reply indicates that @samp{QNonStop} is not supported by the stub. @end table @@ -34685,7 +37201,7 @@ The request succeeded. @item E @var{nn} An error occurred. @var{nn} are hex digits. -@item +@item @w{} An empty reply indicates that @samp{QPassSignals} is not supported by the stub. @end table @@ -34695,6 +37211,48 @@ command (@pxref{Remote Configuration, set remote pass-signals}). This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). +@item QProgramSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} +@cindex signals the inferior may see, remote request +@cindex @samp{QProgramSignals} packet +@anchor{QProgramSignals} +Each listed @var{signal} may be delivered to the inferior process. +Others should be silently discarded. + +In some cases, the remote stub may need to decide whether to deliver a +signal to the program or not without @value{GDBN} involvement. One +example of that is while detaching --- the program's threads may have +stopped for signals that haven't yet had a chance of being reported to +@value{GDBN}, and so the remote stub can use the signal list specified +by this packet to know whether to deliver or ignore those pending +signals. + +This does not influence whether to deliver a signal as requested by a +resumption packet (@pxref{vCont packet}). + +Signals are numbered identically to continue packets and stop replies +(@pxref{Stop Reply Packets}). Each @var{signal} list item should be +strictly greater than the previous item. Multiple +@samp{QProgramSignals} packets do not combine; any earlier +@samp{QProgramSignals} list is completely replaced by the new list. + +Reply: +@table @samp +@item OK +The request succeeded. + +@item E @var{nn} +An error occurred. @var{nn} are hex digits. + +@item @w{} +An empty reply indicates that @samp{QProgramSignals} is not supported +by the stub. +@end table + +Use of this packet is controlled by the @code{set remote program-signals} +command (@pxref{Remote Configuration, set remote program-signals}). +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item qRcmd,@var{command} @cindex execute remote command, remote request @cindex @samp{qRcmd} packet @@ -34713,7 +37271,7 @@ A command response with no output. A command response with the hex encoded output string @var{OUTPUT}. @item E @var{NN} Indicate a badly formed request. -@item +@item @w{} An empty reply indicates that @samp{qRcmd} is not recognized. @end table @@ -34724,7 +37282,10 @@ packets.) @item qSearch:memory:@var{address};@var{length};@var{search-pattern} @cindex searching memory, in remote debugging +@ifnotinfo @cindex @samp{qSearch:memory} packet +@end ifnotinfo +@cindex @samp{qSearch memory} packet @anchor{qSearch memory} Search @var{length} bytes at @var{address} for @var{search-pattern}. @var{address} and @var{length} are encoded in hex. @@ -34738,7 +37299,7 @@ The pattern was not found. The pattern was found at @var{address}. @item E @var{NN} A badly formed request or an error was encountered while searching memory. -@item +@item @w{} An empty reply indicates that @samp{qSearch:memory} is not recognized. @end table @@ -34755,7 +37316,7 @@ The stub has switched to no-acknowledgment mode. @value{GDBN} acknowledges this reponse, but neither the stub nor @value{GDBN} shall send or expect further @samp{+}/@samp{-} acknowledgments in the current connection. -@item +@item @w{} An empty reply indicates that the stub does not support no-acknowledgment mode. @end table @@ -34785,7 +37346,7 @@ Reply: The stub supports or does not support each returned @var{stubfeature}, depending on the form of each @var{stubfeature} (see below for the possible forms). -@item +@item @w{} An empty reply indicates that @samp{qSupported} is not recognized, or that no features needed to be reported to @value{GDBN}. @end table @@ -34891,6 +37452,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{qXfer:btrace:read} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{qXfer:features:read} @tab No @tab @samp{-} @@ -34941,11 +37507,26 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{qXfer:uib:read} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{qXfer:fdpic:read} @tab No @tab @samp{-} @tab Yes +@item @samp{Qbtrace:off} +@tab Yes +@tab @samp{-} +@tab Yes + +@item @samp{Qbtrace:bts} +@tab Yes +@tab @samp{-} +@tab Yes + @item @samp{QNonStop} @tab No @tab @samp{-} @@ -34966,6 +37547,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab No +@item @samp{ConditionalBreakpoints} +@tab No +@tab @samp{-} +@tab No + @item @samp{ConditionalTracepoints} @tab No @tab @samp{-} @@ -34986,6 +37572,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab No +@item @samp{QAgent} +@tab No +@tab @samp{-} +@tab No + @item @samp{QAllow} @tab No @tab @samp{-} @@ -35001,11 +37592,21 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab No +@item @samp{QTBuffer:size} +@tab No +@tab @samp{-} +@tab No + @item @samp{tracenz} @tab No @tab @samp{-} @tab No +@item @samp{BreakpointCommands} +@tab No +@tab @samp{-} +@tab No + @end multitable These are the currently defined stub features, in more detail: @@ -35026,6 +37627,10 @@ byte in its buffer for the NUL. If this stub feature is not supported, The remote stub understands the @samp{qXfer:auxv:read} packet (@pxref{qXfer auxiliary vector read}). +@item qXfer:btrace:read +The remote stub understands the @samp{qXfer:btrace:read} +packet (@pxref{qXfer btrace read}). + @item qXfer:features:read The remote stub understands the @samp{qXfer:features:read} packet (@pxref{qXfer target description read}). @@ -35070,6 +37675,10 @@ The remote stub understands the @samp{qXfer:threads:read} packet The remote stub understands the @samp{qXfer:traceframe-info:read} packet (@pxref{qXfer traceframe info read}). +@item qXfer:uib:read +The remote stub understands the @samp{qXfer:uib:read} +packet (@pxref{qXfer unwind info block}). + @item qXfer:fdpic:read The remote stub understands the @samp{qXfer:fdpic:read} packet (@pxref{qXfer fdpic loadmap read}). @@ -35103,6 +37712,11 @@ indicated it supports them in its @samp{qSupported} request. The remote stub understands the @samp{qXfer:osdata:read} packet ((@pxref{qXfer osdata read}). +@item ConditionalBreakpoints +The target accepts and implements evaluation of conditional expressions +defined for breakpoints. The target will only report breakpoint triggers +when such conditions are true (@pxref{Conditions, ,Break Conditions}). + @item ConditionalTracepoints The remote stub accepts and implements conditional expressions defined for tracepoints (@pxref{Tracepoint Conditions}). @@ -35119,6 +37733,9 @@ The remote stub accepts and implements the reverse step packet The remote stub understands the @samp{QTDPsrc} packet that supplies the source form of tracepoint definitions. +@item QAgent +The remote stub understands the @samp{QAgent} packet. + @item QAllow The remote stub understands the @samp{QAllow} packet. @@ -35138,11 +37755,26 @@ The remote stub supports the @samp{QTEnable} (@pxref{QTEnable}) and @samp{QTDisable} (@pxref{QTDisable}) packets that allow tracepoints to be enabled and disabled while a trace experiment is running. +@item QTBuffer:size +The remote stub supports the @samp{QTBuffer:size} (@pxref{QTBuffer-size}) +packet that allows to change the size of the trace buffer. + @item tracenz @cindex string tracing, in remote protocol The remote stub supports the @samp{tracenz} bytecode for collecting strings. See @ref{Bytecode Descriptions} for details about the bytecode. +@item BreakpointCommands +@cindex breakpoint commands, in remote protocol +The remote stub supports running a breakpoint's command list itself, +rather than reporting the hit to @value{GDBN}. + +@item Qbtrace:off +The remote stub understands the @samp{Qbtrace:off} packet. + +@item Qbtrace:bts +The remote stub understands the @samp{Qbtrace:bts} packet. + @end table @item qSymbol:: @@ -35183,8 +37815,8 @@ encoded). @value{GDBN} will continue to supply the values of symbols @end table @item qTBuffer -@item QTBuffer -@item QTDisconnected +@itemx QTBuffer +@itemx QTDisconnected @itemx QTDP @itemx QTDPsrc @itemx QTDV @@ -35221,10 +37853,10 @@ conventions above. Please don't use this packet as a model for new packets.) @item QTNotes -@item qTP -@item QTSave -@item qTsP -@item qTsV +@itemx qTP +@itemx QTSave +@itemx qTsP +@itemx qTsV @itemx QTStart @itemx QTStop @itemx QTEnable @@ -35261,6 +37893,25 @@ auxiliary vector}. Note @var{annex} must be empty. This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). +@item qXfer:btrace:read:@var{annex}:@var{offset},@var{length} +@anchor{qXfer btrace read} + +Return a description of the current branch trace. +@xref{Branch Trace Format}. The annex part of the generic @samp{qXfer} +packet may have one of the following values: + +@table @code +@item all +Returns all available branch trace. + +@item new +Returns all available branch trace if the branch trace changed since +the last read request. +@end table + +This packet is not probed by default; the remote stub must request it +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item qXfer:features:read:@var{annex}:@var{offset},@var{length} @anchor{qXfer target description read} Access the @dfn{target description}. @xref{Target Descriptions}. The @@ -35357,6 +38008,14 @@ Return a description of the current traceframe's contents. This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). +@item qXfer:uib:read:@var{pc}:@var{offset},@var{length} +@anchor{qXfer unwind info block} + +Return the unwind information block for @var{pc}. This packet is used +on OpenVMS/ia64 to ask the kernel unwind information. + +This packet is not probed by default. + @item qXfer:fdpic:read:@var{annex}:@var{offset},@var{length} @anchor{qXfer fdpic loadmap read} Read contents of @code{loadmap}s on the target system. The @@ -35399,7 +38058,7 @@ The request was malformed, or @var{annex} was invalid. The offset was invalid, or there was an error encountered reading the data. @var{nn} is a hex-encoded @code{errno} value. -@item +@item @w{} An empty reply indicates the @var{object} string was not recognized by the stub, or that the object does not support reading. @end table @@ -35454,7 +38113,7 @@ The request was malformed, or @var{annex} was invalid. The offset was invalid, or there was an error encountered writing the data. @var{nn} is a hex-encoded @code{errno} value. -@item +@item @w{} An empty reply indicates the @var{object} string was not recognized by the stub, or that the object does not support writing. @end table @@ -35489,6 +38148,28 @@ The remote server created a new process. A badly formed request or an error was encountered. @end table +@item Qbtrace:bts +Enable branch tracing for the current thread using bts tracing. + +Reply: +@table @samp +@item OK +Branch tracing has been enabled. +@item E.errtext +A badly formed request or an error was encountered. +@end table + +@item Qbtrace:off +Disable branch tracing for the current thread. + +Reply: +@table @samp +@item OK +Branch tracing has been disabled. +@item E.errtext +A badly formed request or an error was encountered. +@end table + @end table @node Architecture-Specific Protocol Details @@ -35498,9 +38179,21 @@ This section describes how the remote protocol is applied to specific target architectures. Also see @ref{Standard Target Features}, for details of XML target descriptions for each architecture. -@subsection ARM +@menu +* ARM-Specific Protocol Details:: +* MIPS-Specific Protocol Details:: +@end menu + +@node ARM-Specific Protocol Details +@subsection @acronym{ARM}-specific Protocol Details + +@menu +* ARM Breakpoint Kinds:: +@end menu -@subsubsection Breakpoint Kinds +@node ARM Breakpoint Kinds +@subsubsection @acronym{ARM} Breakpoint Kinds +@cindex breakpoint kinds, @acronym{ARM} These breakpoint kinds are defined for the @samp{Z0} and @samp{Z1} packets. @@ -35513,37 +38206,65 @@ These breakpoint kinds are defined for the @samp{Z0} and @samp{Z1} packets. 32-bit Thumb mode (Thumb-2) breakpoint. @item 4 -32-bit ARM mode breakpoint. +32-bit @acronym{ARM} mode breakpoint. @end table -@subsection MIPS +@node MIPS-Specific Protocol Details +@subsection @acronym{MIPS}-specific Protocol Details -@subsubsection Register Packet Format +@menu +* MIPS Register packet Format:: +* MIPS Breakpoint Kinds:: +@end menu + +@node MIPS Register packet Format +@subsubsection @acronym{MIPS} Register Packet Format +@cindex register packet format, @acronym{MIPS} The following @code{g}/@code{G} packets have previously been defined. In the below, some thirty-two bit registers are transferred as sixty-four bits. Those registers should be zero/sign extended (which?) to fill the space allocated. Register bytes are transferred in target byte order. The two nibbles within a register byte are transferred -most-significant - least-significant. +most-significant -- least-significant. @table @r @item MIPS32 - All registers are transferred as thirty-two bit quantities in the order: 32 general-purpose; sr; lo; hi; bad; cause; pc; 32 floating-point registers; fsr; fir; fp. @item MIPS64 - All registers are transferred as sixty-four bit quantities (including thirty-two bit registers such as @code{sr}). The ordering is the same as @code{MIPS32}. @end table +@node MIPS Breakpoint Kinds +@subsubsection @acronym{MIPS} Breakpoint Kinds +@cindex breakpoint kinds, @acronym{MIPS} + +These breakpoint kinds are defined for the @samp{Z0} and @samp{Z1} packets. + +@table @r + +@item 2 +16-bit @acronym{MIPS16} mode breakpoint. + +@item 3 +16-bit @acronym{microMIPS} mode breakpoint. + +@item 4 +32-bit standard @acronym{MIPS} mode breakpoint. + +@item 5 +32-bit @acronym{microMIPS} mode breakpoint. + +@end table + @node Tracepoint Packets @section Tracepoint Packets @cindex tracepoint packets @@ -35555,6 +38276,7 @@ tracepoints (@pxref{Tracepoints}). @table @samp @item QTDP:@var{n}:@var{addr}:@var{ena}:@var{step}:@var{pass}[:F@var{flen}][:X@var{len},@var{bytes}]@r{[}-@r{]} +@cindex @samp{QTDP} packet Create a new tracepoint, number @var{n}, at @var{addr}. If @var{ena} is @samp{E}, then the tracepoint is enabled; if it is @samp{D}, then the tracepoint is disabled. @var{step} is the tracepoint's step @@ -35574,7 +38296,7 @@ Replies: The packet was understood and carried out. @item qRelocInsn @xref{Tracepoint Packets,,Relocate instruction reply packet}. -@item +@item @w{} The packet was not recognized. @end table @@ -35640,7 +38362,7 @@ Replies: The packet was understood and carried out. @item qRelocInsn @xref{Tracepoint Packets,,Relocate instruction reply packet}. -@item +@item @w{} The packet was not recognized. @end table @@ -35689,6 +38411,7 @@ target should simply create the trace state variables as they are mentioned in expressions. @item QTFrame:@var{n} +@cindex @samp{QTFrame} packet Select the @var{n}'th tracepoint frame from the buffer, and use the register and memory contents recorded there to answer subsequent request packets from @value{GDBN}. @@ -35731,6 +38454,7 @@ Like @samp{QTFrame:range:@var{start}:@var{end}}, but select the first frame @emph{outside} the given range of addresses (exclusive). @item qTMinFTPILen +@cindex @samp{qTMinFTPILen} packet This packet requests the minimum length of instruction at which a fast tracepoint (@pxref{Set Tracepoints}) may be placed. For instance, on the 32-bit x86 architecture, it is possible to use a 4-byte jump, but @@ -35750,35 +38474,41 @@ or equal to 1. @var{length} is a hexadecimal number. A reply of 1 means that a fast tracepoint may be placed on any instruction regardless of size. @item E An error has occurred. -@item +@item @w{} An empty reply indicates that the request is not supported by the stub. @end table @item QTStart +@cindex @samp{QTStart} packet Begin the tracepoint experiment. Begin collecting data from tracepoint hits in the trace frame buffer. This packet supports the @samp{qRelocInsn} reply (@pxref{Tracepoint Packets,,Relocate instruction reply packet}). @item QTStop +@cindex @samp{QTStop} packet End the tracepoint experiment. Stop collecting trace frames. @item QTEnable:@var{n}:@var{addr} @anchor{QTEnable} +@cindex @samp{QTEnable} packet Enable tracepoint @var{n} at address @var{addr} in a started tracepoint experiment. If the tracepoint was previously disabled, then collection of data from it will resume. @item QTDisable:@var{n}:@var{addr} @anchor{QTDisable} +@cindex @samp{QTDisable} packet Disable tracepoint @var{n} at address @var{addr} in a started tracepoint experiment. No more data will be collected from the tracepoint unless @samp{QTEnable:@var{n}:@var{addr}} is subsequently issued. @item QTinit +@cindex @samp{QTinit} packet Clear the table of tracepoints, and empty the trace frame buffer. @item QTro:@var{start1},@var{end1}:@var{start2},@var{end2}:@dots{} +@cindex @samp{QTro} packet Establish the given ranges of memory as ``transparent''. The stub will answer requests for these ranges from memory's current contents, if they were not collected as part of the tracepoint hit. @@ -35789,12 +38519,14 @@ still have the same contents they did when the tracepoint was hit, so there's no reason for the stub to refuse to provide their contents. @item QTDisconnected:@var{value} +@cindex @samp{QTDisconnected} packet Set the choice to what to do with the tracing run when @value{GDBN} disconnects from the target. A @var{value} of 1 directs the target to continue the tracing run, while 0 tells the target to stop tracing if @value{GDBN} is no longer in the picture. @item qTStatus +@cindex @samp{qTStatus} packet Ask the stub if there is a trace experiment running right now. The reply has the form: @@ -35914,7 +38646,9 @@ was not collected. @end table @item qTfP +@cindex @samp{qTfP} packet @itemx qTsP +@cindex @samp{qTsP} packet These packets request data about tracepoints that are being used by the target. @value{GDBN} sends @code{qTfP} to get the first piece of data, and multiple @code{qTsP} to get additional pieces. Replies @@ -35922,7 +38656,9 @@ to these packets generally take the form of the @code{QTDP} packets that define tracepoints. (FIXME add detailed syntax) @item qTfV +@cindex @samp{qTfV} packet @itemx qTsV +@cindex @samp{qTsV} packet These packets request data about trace state variables that are on the target. @value{GDBN} sends @code{qTfV} to get the first vari of data, and multiple @code{qTsV} to get additional variables. Replies to @@ -35931,6 +38667,10 @@ trace state variables. @item qTfSTM @itemx qTsSTM +@anchor{qTfSTM} +@anchor{qTsSTM} +@cindex @samp{qTfSTM} packet +@cindex @samp{qTsSTM} packet These packets request data about static tracepoint markers that exist in the target program. @value{GDBN} sends @code{qTfSTM} to get the first piece of data, and multiple @code{qTsSTM} to get additional @@ -35946,7 +38686,7 @@ a comma-separated list of markers (lower case letter @samp{L}) denotes end of list. @item E @var{nn} An error occurred. @var{nn} are hex digits. -@item +@item @w{} An empty reply indicates that the request is not supported by the stub. @end table @@ -35961,18 +38701,22 @@ query), until the target responds with @samp{l} (lower-case ell, for @dfn{last}). @item qTSTMat:@var{address} +@anchor{qTSTMat} +@cindex @samp{qTSTMat} packet This packets requests data about static tracepoint markers in the target program at @var{address}. Replies to this packet follow the syntax of the @samp{qTfSTM} and @code{qTsSTM} packets that list static tracepoint markers. @item QTSave:@var{filename} +@cindex @samp{QTSave} packet This packet directs the target to save trace data to the file name @var{filename} in the target's filesystem. @var{filename} is encoded as a hex string; the interpretation of the file name (relative vs absolute, wild cards, etc) is up to the target. @item qTBuffer:@var{offset},@var{len} +@cindex @samp{qTBuffer} packet Return up to @var{len} bytes of the current contents of trace buffer, starting at @var{offset}. The trace buffer is treated as if it were a contiguous collection of traceframes, as per the trace file format. @@ -35985,7 +38729,15 @@ available. This packet directs the target to use a circular trace buffer if @var{value} is 1, or a linear buffer if the value is 0. +@item QTBuffer:size:@var{size} +@anchor{QTBuffer-size} +@cindex @samp{QTBuffer size} packet +This packet directs the target to make the trace buffer be of size +@var{size} if possible. A value of @code{-1} tells the target to +use whatever size it prefers. + @item QTNotes:@r{[}@var{type}:@var{text}@r{]}@r{[};@var{type}:@var{text}@r{]}@dots{} +@cindex @samp{QTNotes} packet This packet adds optional textual notes to the trace run. Allowable types include @code{user}, @code{notes}, and @code{tstop}, the @var{text} fields are arbitrary strings, hex-encoded. @@ -36078,7 +38830,7 @@ normal way (@pxref{Binary Data}). See the individual packet documentation for the interpretation of @var{result} and @var{attachment}. -@item +@item @w{} An empty response indicates that this operation is not recognized. @end table @@ -36126,6 +38878,16 @@ error occurred. Delete the file at @var{pathname} on the target. Return 0, or -1 if an error occurs. @var{pathname} is a string. +@item vFile:readlink: @var{filename} +Read value of symbolic link @var{filename} on the target. Return +the number of bytes read, or -1 if an error occurs. + +The data read should be returned as a binary attachment on success. +If zero bytes were read, the response should include an empty binary +attachment (i.e.@: a trailing semicolon). The return value is the +number of target bytes read; the binary attachment may be longer if +some characters were escaped. + @end table @node Interrupts @@ -36210,17 +38972,91 @@ transmit notifications without fear of confusing older clients. There are no notifications defined for @value{GDBN} to send at the moment, but we assume that most older stubs would ignore them, as well.) -The following notification packets from the stub to @value{GDBN} are -defined: - +Each notification is comprised of three parts: @table @samp -@item Stop: @var{reply} -Report an asynchronous stop event in non-stop mode. -The @var{reply} has the form of a stop reply, as +@item @var{name}:@var{event} +The notification packet is sent by the side that initiates the +exchange (currently, only the stub does that), with @var{event} +carrying the specific information about the notification. +@var{name} is the name of the notification. +@item @var{ack} +The acknowledge sent by the other side, usually @value{GDBN}, to +acknowledge the exchange and request the event. +@end table + +The purpose of an asynchronous notification mechanism is to report to +@value{GDBN} that something interesting happened in the remote stub. + +The remote stub may send notification @var{name}:@var{event} +at any time, but @value{GDBN} acknowledges the notification when +appropriate. The notification event is pending before @value{GDBN} +acknowledges. Only one notification at a time may be pending; if +additional events occur before @value{GDBN} has acknowledged the +previous notification, they must be queued by the stub for later +synchronous transmission in response to @var{ack} packets from +@value{GDBN}. Because the notification mechanism is unreliable, +the stub is permitted to resend a notification if it believes +@value{GDBN} may not have received it. + +Specifically, notifications may appear when @value{GDBN} is not +otherwise reading input from the stub, or when @value{GDBN} is +expecting to read a normal synchronous response or a +@samp{+}/@samp{-} acknowledgment to a packet it has sent. +Notification packets are distinct from any other communication from +the stub so there is no ambiguity. + +After receiving a notification, @value{GDBN} shall acknowledge it by +sending a @var{ack} packet as a regular, synchronous request to the +stub. Such acknowledgment is not required to happen immediately, as +@value{GDBN} is permitted to send other, unrelated packets to the +stub first, which the stub should process normally. + +Upon receiving a @var{ack} packet, if the stub has other queued +events to report to @value{GDBN}, it shall respond by sending a +normal @var{event}. @value{GDBN} shall then send another @var{ack} +packet to solicit further responses; again, it is permitted to send +other, unrelated packets as well which the stub should process +normally. + +If the stub receives a @var{ack} packet and there are no additional +@var{event} to report, the stub shall return an @samp{OK} response. +At this point, @value{GDBN} has finished processing a notification +and the stub has completed sending any queued events. @value{GDBN} +won't accept any new notifications until the final @samp{OK} is +received . If further notification events occur, the stub shall send +a new notification, @value{GDBN} shall accept the notification, and +the process shall be repeated. + +The process of asynchronous notification can be illustrated by the +following example: +@smallexample +<- @code{%%Stop:T0505:98e7ffbf;04:4ce6ffbf;08:b1b6e54c;thread:p7526.7526;core:0;} +@code{...} +-> @code{vStopped} +<- @code{T0505:68f37db7;04:40f37db7;08:63850408;thread:p7526.7528;core:0;} +-> @code{vStopped} +<- @code{T0505:68e3fdb6;04:40e3fdb6;08:63850408;thread:p7526.7529;core:0;} +-> @code{vStopped} +<- @code{OK} +@end smallexample + +The following notifications are defined: +@multitable @columnfractions 0.12 0.12 0.38 0.38 + +@item Notification +@tab Ack +@tab Event +@tab Description + +@item Stop +@tab vStopped +@tab @var{reply}. The @var{reply} has the form of a stop reply, as described in @ref{Stop Reply Packets}. Refer to @ref{Remote Non-Stop}, for information on how these notifications are acknowledged by @value{GDBN}. -@end table +@tab Report an asynchronous stop event in non-stop mode. + +@end multitable @node Remote Non-Stop @section Remote Protocol Support for Non-Stop Mode @@ -36249,45 +39085,6 @@ affected thread is stopped; any other still-running threads continue to run. When reporting a @samp{W} or @samp{X} response, all running threads belonging to other attached processes continue to run. -Only one stop reply notification at a time may be pending; if -additional stop events occur before @value{GDBN} has acknowledged the -previous notification, they must be queued by the stub for later -synchronous transmission in response to @samp{vStopped} packets from -@value{GDBN}. Because the notification mechanism is unreliable, -the stub is permitted to resend a stop reply notification -if it believes @value{GDBN} may not have received it. @value{GDBN} -ignores additional stop reply notifications received before it has -finished processing a previous notification and the stub has completed -sending any queued stop events. - -Otherwise, @value{GDBN} must be prepared to receive a stop reply -notification at any time. Specifically, they may appear when -@value{GDBN} is not otherwise reading input from the stub, or when -@value{GDBN} is expecting to read a normal synchronous response or a -@samp{+}/@samp{-} acknowledgment to a packet it has sent. -Notification packets are distinct from any other communication from -the stub so there is no ambiguity. - -After receiving a stop reply notification, @value{GDBN} shall -acknowledge it by sending a @samp{vStopped} packet (@pxref{vStopped packet}) -as a regular, synchronous request to the stub. Such acknowledgment -is not required to happen immediately, as @value{GDBN} is permitted to -send other, unrelated packets to the stub first, which the stub should -process normally. - -Upon receiving a @samp{vStopped} packet, if the stub has other queued -stop events to report to @value{GDBN}, it shall respond by sending a -normal stop reply response. @value{GDBN} shall then send another -@samp{vStopped} packet to solicit further responses; again, it is -permitted to send other, unrelated packets as well which the stub -should process normally. - -If the stub receives a @samp{vStopped} packet and there are no -additional stop events to report, the stub shall return an @samp{OK} -response. At this point, if further stop events occur, the stub shall -send a new stop reply notification, @value{GDBN} shall accept the -notification, and the process shall be repeated. - In non-stop mode, the target shall respond to the @samp{?} packet as follows. First, any incomplete stop reply notification/@samp{vStopped} sequence in progress is abandoned. The target must begin a new @@ -37831,6 +40628,56 @@ The formal DTD for the traceframe info format is given below: length CDATA #REQUIRED> @end smallexample +@node Branch Trace Format +@section Branch Trace Format +@cindex branch trace format + +In order to display the branch trace of an inferior thread, +@value{GDBN} needs to obtain the list of branches. This list is +represented as list of sequential code blocks that are connected via +branches. The code in each block has been executed sequentially. + +This list is obtained using the @samp{qXfer:btrace:read} +(@pxref{qXfer btrace read}) packet and is an XML document. + +@value{GDBN} must be linked with the Expat library to support XML +traceframe info discovery. @xref{Expat}. + +The top-level structure of the document is shown below: + +@smallexample + + + + block... + +@end smallexample + +@itemize + +@item +A block of sequentially executed instructions starting at @var{begin} +and ending at @var{end}: + +@smallexample + +@end smallexample + +@end itemize + +The formal DTD for the branch trace format is given below: + +@smallexample + + + + + +@end smallexample + @include agentexpr.texi @node Target Descriptions @@ -37840,7 +40687,7 @@ The formal DTD for the traceframe info format is given below: One of the challenges of using @value{GDBN} to debug embedded systems is that there are so many minor variants of each processor architecture in use. It is common practice for vendors to start with -a standard processor core --- ARM, PowerPC, or MIPS, for example --- +a standard processor core --- ARM, PowerPC, or @acronym{MIPS}, for example --- and then make changes to adapt it to a particular market niche. Some architectures have hundreds of variants, available from dozens of vendors. This leads to a number of problems: @@ -38288,6 +41135,7 @@ of recognizing standard features, but @value{GDBN} will only display registers using the capitalization used in the description. @menu +* AArch64 Features:: * ARM Features:: * i386 Features:: * MIPS Features:: @@ -38297,6 +41145,18 @@ registers using the capitalization used in the description. @end menu +@node AArch64 Features +@subsection AArch64 Features +@cindex target descriptions, AArch64 features + +The @samp{org.gnu.gdb.aarch64.core} feature is required for AArch64 +targets. It should contain registers @samp{x0} through @samp{x30}, +@samp{sp}, @samp{pc}, and @samp{cpsr}. + +The @samp{org.gnu.gdb.aarch64.fpu} feature is optional. If present, +it should contain registers @samp{v0} through @samp{v31}, @samp{fpsr}, +and @samp{fpcr}. + @node ARM Features @subsection ARM Features @cindex target descriptions, ARM features @@ -38383,10 +41243,10 @@ The @samp{org.gnu.gdb.i386.linux} feature is optional. It should describe a single register, @samp{orig_eax}. @node MIPS Features -@subsection MIPS Features -@cindex target descriptions, MIPS features +@subsection @acronym{MIPS} Features +@cindex target descriptions, @acronym{MIPS} features -The @samp{org.gnu.gdb.mips.cpu} feature is required for MIPS targets. +The @samp{org.gnu.gdb.mips.cpu} feature is required for @acronym{MIPS} targets. It should contain registers @samp{r0} through @samp{r31}, @samp{lo}, @samp{hi}, and @samp{pc}. They may be 32-bit or 64-bit depending on the target. @@ -38400,6 +41260,11 @@ it may be optional in a future version of @value{GDBN}. It should contain registers @samp{f0} through @samp{f31}, @samp{fcsr}, and @samp{fir}. They may be 32-bit or 64-bit depending on the target. +The @samp{org.gnu.gdb.mips.dsp} feature is optional. It should +contain registers @samp{hi1} through @samp{hi3}, @samp{lo1} through +@samp{lo3}, and @samp{dspctl}. The @samp{dspctl} register should +be 32-bit and the rest may be 32-bit or 64-bit depending on the target. + The @samp{org.gnu.gdb.mips.linux} feature is optional. It should contain a single register, @samp{restart}, which is used by the Linux kernel to control restartable syscalls. @@ -38601,8 +41466,18 @@ unless otherwise noted: @enumerate @item -The version number, currently 5. Versions 1, 2 and 3 are obsolete. -Version 4 differs by its hashing function. +The version number, currently 8. Versions 1, 2 and 3 are obsolete. +Version 4 uses a different hashing function from versions 5 and 6. +Version 6 includes symbols for inlined functions, whereas versions 4 +and 5 do not. Version 7 adds attributes to the CU indices in the +symbol table. Version 8 specifies that symbols from DWARF type units +(@samp{DW_TAG_type_unit}) refer to the type unit's symbol table and not the +compilation unit (@samp{DW_TAG_comp_unit}) using the type. + +@value{GDBN} will only read version 4, 5, or 6 indices +by specifying @code{set use-deprecated-index-sections on}. +GDB has a workaround for potentially broken version 7 indices so it is +currently not flagged as deprecated. @item The offset, from the start of the file, of the CU list. @@ -38677,7 +41552,7 @@ index version: @item Version 4 The formula is @code{r = r * 67 + c - 113}. -@item Version 5 +@item Versions 5 to 7 The formula is @code{r = r * 67 + tolower (c) - 113}. @end table @@ -38701,26 +41576,121 @@ strings. A CU vector in the constant pool is a sequence of @code{offset_type} values. The first value is the number of CU indices in the vector. -Each subsequent value is the index of a CU in the CU list. This -element in the hash table is used to indicate which CUs define the -symbol. +Each subsequent value is the index and symbol attributes of a CU in +the CU list. This element in the hash table is used to indicate which +CUs define the symbol and how the symbol is used. +See below for the format of each CU index+attributes entry. A string in the constant pool is zero-terminated. @end enumerate +Attributes were added to CU index values in @code{.gdb_index} version 7. +If a symbol has multiple uses within a CU then there is one +CU index+attributes value for each use. + +The format of each CU index+attributes entry is as follows +(bit 0 = LSB): + +@table @asis + +@item Bits 0-23 +This is the index of the CU in the CU list. +@item Bits 24-27 +These bits are reserved for future purposes and must be zero. +@item Bits 28-30 +The kind of the symbol in the CU. + +@table @asis +@item 0 +This value is reserved and should not be used. +By reserving zero the full @code{offset_type} value is backwards compatible +with previous versions of the index. +@item 1 +The symbol is a type. +@item 2 +The symbol is a variable or an enum value. +@item 3 +The symbol is a function. +@item 4 +Any other kind of symbol. +@item 5,6,7 +These values are reserved. +@end table + +@item Bit 31 +This bit is zero if the value is global and one if it is static. + +The determination of whether a symbol is global or static is complicated. +The authorative reference is the file @file{dwarf2read.c} in +@value{GDBN} sources. + +@end table + +This pseudo-code describes the computation of a symbol's kind and +global/static attributes in the index. + +@smallexample +is_external = get_attribute (die, DW_AT_external); +language = get_attribute (cu_die, DW_AT_language); +switch (die->tag) + @{ + case DW_TAG_typedef: + case DW_TAG_base_type: + case DW_TAG_subrange_type: + kind = TYPE; + is_static = 1; + break; + case DW_TAG_enumerator: + kind = VARIABLE; + is_static = (language != CPLUS && language != JAVA); + break; + case DW_TAG_subprogram: + kind = FUNCTION; + is_static = ! (is_external || language == ADA); + break; + case DW_TAG_constant: + kind = VARIABLE; + is_static = ! is_external; + break; + case DW_TAG_variable: + kind = VARIABLE; + is_static = ! is_external; + break; + case DW_TAG_namespace: + kind = TYPE; + is_static = 0; + break; + case DW_TAG_class_type: + case DW_TAG_interface_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_enumeration_type: + kind = TYPE; + is_static = (language != CPLUS && language != JAVA); + break; + default: + assert (0); + @} +@end smallexample + @include gpl.texi @node GNU Free Documentation License @appendix GNU Free Documentation License @include fdl.texi -@node Index -@unnumbered Index +@node Concept Index +@unnumbered Concept Index @printindex cp +@node Command and Variable Index +@unnumbered Command, Variable, and Function Index + +@printindex fn + @tex -% I think something like @colophon should be in texinfo. In the +% I think something like @@colophon should be in texinfo. In the % meantime: \long\def\colophon{\hbox to0pt{}\vfill \centerline{The body of this manual is set in} @@ -38732,7 +41702,7 @@ A string in the constant pool is zero-terminated. \centerline{{\sl\fontname\tensl\/}} \centerline{are used for emphasis.}\vfill} \page\colophon -% Blame: doc@cygnus.com, 1991. +% Blame: doc@@cygnus.com, 1991. @end tex @bye diff --git a/contrib/gdb-7/gdb/doc/gdbint.texinfo b/contrib/gdb-7/gdb/doc/gdbint.texinfo index 1845124bc9..4a75c26c59 100644 --- a/contrib/gdb-7/gdb/doc/gdbint.texinfo +++ b/contrib/gdb-7/gdb/doc/gdbint.texinfo @@ -9,8 +9,7 @@ @end direntry @copying -Copyright @copyright{} 1990-1994, 1996, 1998-2006, 2008-2012 Free -Software Foundation, Inc. +Copyright @copyright{} 1990-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions. Written by John Gilmore. Second Edition by Stan Shebs. @@ -28,13 +27,11 @@ This file documents the internals of the GNU debugger @value{GDBN}. @insertcopying @end ifnottex - -@syncodeindex fn cp -@syncodeindex vr cp +@syncodeindex vr fn @titlepage @title @value{GDBN} Internals -@subtitle{A guide to the internals of the GNU debugger} +@subtitle A guide to the internals of the GNU debugger @author John Gilmore @author Cygnus Solutions @author Second Edition: @@ -93,7 +90,8 @@ as the mechanisms that adapt @value{GDBN} to specific hosts and targets. * GDB Observers:: @value{GDBN} Currently available observers * GNU Free Documentation License:: The license for this documentation -* Index:: +* Concept Index:: +* Function and Variable Index:: @end menu @node Summary @@ -2740,14 +2738,6 @@ are: The default name of @value{GDBN}'s initialization file (normally @file{.gdbinit}). -@item SIGWINCH_HANDLER -If your host defines @code{SIGWINCH}, you can define this to be the name -of a function to be called if @code{SIGWINCH} is received. - -@item SIGWINCH_HANDLER_BODY -Define this to expand into code that will define the function named by -the expansion of @code{SIGWINCH_HANDLER}. - @item CRLF_SOURCE_FILES @cindex DOS text files Define this if host files use @code{\r\n} rather than @code{\n} as a @@ -2770,11 +2760,6 @@ Substitute for isatty, if not available. @item FOPEN_RB Define this if binary files are opened the same way as text files. -@item CC_HAS_LONG_LONG -@cindex @code{long long} data type -Define this if the host C compiler supports @code{long long}. This is set -by the @code{configure} script. - @item PRINTF_HAS_LONG_LONG Define this if the host can handle printing of long long integers via the printf format conversion specifier @code{ll}. This is set by the @@ -4541,8 +4526,11 @@ contents and size of a breakpoint instruction. It returns a pointer to a static string of bytes that encode a breakpoint instruction, stores the length of the string to @code{*@var{lenptr}}, and adjusts the program counter (if necessary) to point to the actual memory location where the -breakpoint should be inserted. May return @code{NULL} to indicate that -software breakpoints are not supported. +breakpoint should be inserted. On input, the program counter +(@code{*@var{pcptr}} is the encoded inferior's PC register. If software +breakpoints are supported, the function sets this argument to the PC's +plain address. If software breakpoints are not supported, the function +returns NULL instead of the encoded breakpoint instruction. Although it is common to use a trap instruction for a breakpoint, it's not required; for instance, the bit pattern could be an invalid @@ -4822,7 +4810,7 @@ instead of value. @anchor{gdbarch_push_dummy_call} Define this to push the dummy frame's call to the inferior function onto the stack. In addition to pushing @var{nargs}, the code should push @var{struct_addr} (when @var{struct_return} is non-zero), and -the return address (@var{bp_addr}). +the return address (@var{bp_addr}, in inferior's PC register encoding). @var{function} is a pointer to a @code{struct value}; on architectures that use function descriptors, this contains the function descriptor value. @@ -4836,12 +4824,14 @@ instruction sequence (including space for a breakpoint) to which the called function should return. Set @var{bp_addr} to the address at which the breakpoint instruction -should be inserted, @var{real_pc} to the resume address when starting -the call sequence, and return the updated inner-most stack address. +should be inserted (in inferior's PC register encoding), @var{real_pc} to the +resume address when starting the call sequence, and return the updated +inner-most stack address. By default, the stack is grown sufficient to hold a frame-aligned (@pxref{frame_align}) breakpoint, @var{bp_addr} is set to the address -reserved for that breakpoint, and @var{real_pc} set to @var{funaddr}. +reserved for that breakpoint (in inferior's PC register encoding), and +@var{real_pc} set to @var{funaddr}. This method replaces @w{@code{gdbarch_call_dummy_location (@var{gdbarch})}}. @@ -4916,11 +4906,6 @@ number of that register. Use this function to convert stab register @var{stab_regnr} into @value{GDBN} regnum. If not defined, no conversion will be done. -@item SYMBOL_RELOADING_DEFAULT -@findex SYMBOL_RELOADING_DEFAULT -The default value of the ``symbol-reloading'' variable. (Never defined in -current sources.) - @item TARGET_CHAR_BIT @findex TARGET_CHAR_BIT Number of bits in a char; defaults to 8. @@ -5849,6 +5834,26 @@ the following guidelines: @tab (pointer dereference) @end multitable +Any two or more lines in code should be wrapped in braces, even if +they are comments, as they look like separate statements: + +@smallexample +if (i) + @{ + /* Return success. */ + return 0; + @} +@end smallexample + +@noindent +and not: + +@smallexample +if (i) + /* Return success. */ + return 0; +@end smallexample + @subsection Comments @cindex comment formatting @@ -5901,6 +5906,25 @@ protected with parentheses.) Declarations like @samp{struct foo *} should be used in preference to declarations like @samp{typedef struct foo @{ @dots{} @} *foo_ptr}. +Zero constant (@code{0}) is not interchangeable with a null pointer +constant (@code{NULL}) anywhere. @sc{gcc} does not give a warning for +such interchange. Specifically: + +@multitable @columnfractions .2 .5 +@item incorrect +@tab @code{if (pointervar) @{@}} +@item incorrect +@tab @code{if (!pointervar) @{@}} +@item incorrect +@tab @code{if (pointervar != 0) @{@}} +@item incorrect +@tab @code{if (pointervar == 0) @{@}} +@item correct +@tab @code{if (pointervar != NULL) @{@}} +@item correct +@tab @code{if (pointervar == NULL) @{@}} +@end multitable + @subsection Function Prototypes @cindex function prototypes @@ -5910,7 +5934,8 @@ argument type and name, with the name matching that used in the actual function definition. All external functions should have a declaration in a header file that -callers include, except for @code{_initialize_*} functions, which must +callers include, that declaration should use the @code{extern} modifier. +The only exception concerns @code{_initialize_*} functions, which must be external so that @file{init.c} construction works, but shouldn't be visible to random source files. @@ -6798,35 +6823,9 @@ Update the copyright year in: @end itemize @item -Run the @file{copyright.sh} script to add the new year in the copyright -notices of most source files. This script requires Emacs 22 or later to -be installed. - -@item -The new year also needs to be added manually in all other files that -are not already taken care of by the @file{copyright.sh} script: -@itemize @bullet - @item - @file{*.s} - @item - @file{*.f} - @item - @file{*.f90} - @item - @file{*.igen} - @item - @file{*.ac} - @item - @file{*.texi} - @item - @file{*.texinfo} - @item - @file{*.tex} - @item - @file{*.defs} - @item - @file{*.1} -@end itemize +Run the @file{copyright.py} Python script to add the new year in the copyright +notices of most source files. This script has been tested with Python +2.6 and 2.7. @end itemize @@ -7689,7 +7688,7 @@ make check RUNTESTFLAGS="GDB=/usr/bin/gdb GDBSERVER=/usr/bin/gdbserver" When running the testsuite normally one doesn't want whatever is in @file{~/.gdbinit} to interfere with the tests, therefore the test harness passes @option{-nx} to @value{GDBN}. One also doesn't want any windowed -version of @value{GDBN}, e.g., @command{gdbtui}, to run. +version of @value{GDBN}, e.g., @samp{gdb -tui}, to run. This is achieved via @code{INTERNAL_GDBFLAGS}. @smallexample @@ -7845,6 +7844,96 @@ instance, some @value{GDBN} bugs involving the display of source lines would never manifest themselves if the programs used GNU coding style uniformly. +Some testcase results need more detailed explanation: + +@table @code +@item KFAIL +Known problem of @value{GDBN} itself. You must specify the @value{GDBN} bug +report number like in these sample tests: +@smallexample +kfail "gdb/13392" "continue to marker 2" +@end smallexample +or +@smallexample +setup_kfail gdb/13392 "*-*-*" +kfail "continue to marker 2" +@end smallexample + +@item XFAIL +Known problem of environment. This typically includes @value{NGCC} but it +includes also many other system components which cannot be fixed in the +@value{GDBN} project. Sample test with sanity check not knowing the specific +cause of the problem: +@smallexample +# On x86_64 it is commonly about 4MB. +if @{$stub_size > 25000000@} @{ + xfail "stub size $stub_size is too large" + return +@} +@end smallexample + +You should provide bug report number for the failing component of the +environment, if such bug report is available: +@smallexample +if @{[test_compiler_info @{gcc-[0-3]-*@}] + || [test_compiler_info @{gcc-4-[0-5]-*@}]@} @{ + setup_xfail "gcc/46955" *-*-* +@} +gdb_test "python print ttype.template_argument(2)" "&C::c" +@end smallexample +@end table + +@section Board settings +In @value{GDBN} testsuite, the tests can be configured or customized in the board +file by means of @dfn{Board Settings}. Each setting should be consulted by +test cases that depend on the corresponding feature. + +Here are the supported board settings: + +@table @code + +@item gdb,cannot_call_functions +The board does not support inferior call, that is, invoking inferior functions +in @value{GDBN}. +@item gdb,can_reverse +The board supports reverse execution. +@item gdb,no_hardware_watchpoints +The board does not support hardware watchpoints. +@item gdb,nofileio +@value{GDBN} is unable to intercept target file operations in remote and perform +them on the host. +@item gdb,noinferiorio +The board is unable to provide I/O capability to the inferior. +@c @item gdb,noresults +@c NEED DOCUMENT. +@item gdb,nosignals +The board does not support signals. +@item gdb,skip_huge_test +Skip time-consuming tests on the board with slow connection. +@item gdb,skip_float_tests +Skip tests related to float points on target board. +@item gdb,use_precord +The board supports process record. +@item gdb_server_prog +The location of GDBserver. If GDBserver somewhere other than its default +location is used in test, specify the location of GDBserver in this variable. +The location is a file name of GDBserver that can be either absolute or +relative to testsuite subdirectory in build directory. +@item in_proc_agent +The location of in-process agent. If in-process agent other than its default +location is used in test, specify the location of in-process agent in +this variable. The location is a file name of in-process agent that can be +either absolute or relative to testsuite subdirectory in build directory. +@item noargs +@value{GDBN} does not support argument passing for inferior. +@item no_long_long +The board does not support type @code{long long}. +@c @item use_cygmon +@c NEED DOCUMENT. +@item use_gdb_stub +The tests are running with gdb stub. +@end table + @node Hints @chapter Hints @@ -7952,11 +8041,11 @@ debugged in another. Rather than typing the command @kbd{@w{./gdb ./gdb}}, which works on Suns and such, you can copy @file{gdb} to @file{gdb2} and then type @kbd{@w{./gdb ./gdb2}}. -When you run @value{GDBN} in the @value{GDBN} source directory, it will read a -@file{.gdbinit} file that sets up some simple things to make debugging -gdb easier. The @code{info} command, when executed without a subcommand -in a @value{GDBN} being debugged by gdb, will pop you back up to the top level -gdb. See @file{.gdbinit} for details. +When you run @value{GDBN} in the @value{GDBN} source directory, it will read +@file{gdb-gdb.gdb} file (plus possibly @file{gdb-gdb.py} file) that sets up +some simple things to make debugging gdb easier. The @code{info} command, when +executed without a subcommand in a @value{GDBN} being debugged by gdb, will pop +you back up to the top level gdb. See @file{gdb-gdb.gdb} for details. If you use emacs, you will probably want to do a @code{make TAGS} after you configure your distribution; this will put the machine dependent @@ -8053,9 +8142,14 @@ in the directory the script was called from. @appendix GNU Free Documentation License @include fdl.texi -@node Index -@unnumbered Index +@node Concept Index +@unnumbered Concept Index @printindex cp +@node Function and Variable Index +@unnumbered Function and Variable Index + +@printindex fn + @bye diff --git a/contrib/gdb-7/gdb/doc/observer.texi b/contrib/gdb-7/gdb/doc/observer.texi index 24233cbeb4..adb70857d8 100644 --- a/contrib/gdb-7/gdb/doc/observer.texi +++ b/contrib/gdb-7/gdb/doc/observer.texi @@ -2,7 +2,7 @@ @c This file is part of the GDB manual. @c -@c Copyright (C) 2003-2006, 2008-2012 Free Software Foundation, Inc. +@c Copyright (C) 2003-2013 Free Software Foundation, Inc. @c @c See the file gdbint.texinfo for copying conditions. @c @@ -113,6 +113,13 @@ at the entry-point instruction. For @samp{attach} and @samp{core}, inferior, and before any information on the inferior has been printed. @end deftypefun +@deftypefun void record_changed (struct inferior *@var{inferior}, int @var{started}) +The status of process record for inferior @var{inferior} in +@value{GDBN} has changed. The process record is started if +@var{started} is true, and the process record is stopped if +@var{started} is false. +@end deftypefun + @deftypefun void solib_loaded (struct so_list *@var{solib}) The shared library specified by @var{solib} has been loaded. Note that when @value{GDBN} calls this observer, the library's symbols probably @@ -172,19 +179,11 @@ A breakpoint has been modified in some way. The argument @var{b} is the modified breakpoint. @end deftypefun -@deftypefun void tracepoint_created (int @var{tpnum}) -A new tracepoint has been created. The argument @var{tpnum} is the -number of the newly-created tracepoint. -@end deftypefun - -@deftypefun void tracepoint_deleted (int @var{tpnum}) -A tracepoint has been destroyed. The argument @var{tpnum} is the -number of the newly-destroyed tracepoint. -@end deftypefun - -@deftypefun void tracepoint_modified (int @var{tpnum}) -A tracepoint has been modified in some way. The argument @var{tpnum} -is the number of the modified tracepoint. +@deftypefun void traceframe_changed (int @var{tfnum}, int @var{tpnum}) +The trace frame is changed to @var{tfnum} (e.g., by using the +@code{tfind} command). If @var{tfnum} is negative, it means +@value{GDBN} resumes live debugging. The number of the tracepoint +associated with this traceframe is @var{tpnum}. @end deftypefun @deftypefun void architecture_changed (struct gdbarch *@var{newarch}) @@ -216,9 +215,9 @@ The inferior @var{inf} has been removed from the list of inferiors. This method is called immediately before freeing @var{inf}. @end deftypefun -@deftypefun void memory_changed (CORE_ADDR @var{addr}, int @var{len}, const bfd_byte *@var{data}) +@deftypefun void memory_changed (struct inferior *@var{inferior}, CORE_ADDR @var{addr}, ssize_t @var{len}, const bfd_byte *@var{data}) Bytes from @var{data} to @var{data} + @var{len} have been written -to the current inferior at @var{addr}. +to the @var{inferior} at @var{addr}. @end deftypefun @deftypefun void before_prompt (const char *@var{current_prompt}) @@ -226,6 +225,30 @@ Called before a top-level prompt is displayed. @var{current_prompt} is the current top-level prompt. @end deftypefun +@deftypefun void gdb_datadir_changed (void) +Variable gdb_datadir has been set. The value may not necessarily change. +@end deftypefun + +@deftypefun void command_param_changed (const char *@var{param}, const char *@var{value}) +The parameter of some @code{set} commands in console are changed. This +method is called after a command @code{set @var{param} @var{value}}. +@var{param} is the parameter of @code{set} command, and @var{value} +is the value of changed parameter. +@end deftypefun + +@deftypefun void tsv_created (const struct trace_state_variable *@var{tsv}) +The new trace state variable @var{tsv} is created. +@end deftypefun + +@deftypefun void tsv_deleted (const struct trace_state_variable *@var{tsv}) +The trace state variable @var{tsv} is deleted. If @var{tsv} is +@code{NULL}, all trace state variables are deleted. +@end deftypefun + +@deftypefun void tsv_modified (const struct trace_state_variable *@var{tsv}) +The trace state value @var{tsv} is modified. +@end deftypefun + @deftypefun void test_notification (int @var{somearg}) This observer is used for internal testing. Do not use. See testsuite/gdb.gdb/observer.exp. diff --git a/contrib/gdb-7/gdb/doc/stabs.texinfo b/contrib/gdb-7/gdb/doc/stabs.texinfo index f5a61eb379..a81d0937e1 100644 --- a/contrib/gdb-7/gdb/doc/stabs.texinfo +++ b/contrib/gdb-7/gdb/doc/stabs.texinfo @@ -13,8 +13,7 @@ @end direntry @copying -Copyright @copyright{} 1992-1995, 1997-1998, 2000-2007, 2009-2012 Free -Software Foundation, Inc. +Copyright @copyright{} 1992-2013 Free Software Foundation, Inc. Contributed by Cygnus Support. Written by Julia Menapace, Jim Kingdon, and David MacKenzie. @@ -73,8 +72,8 @@ This document describes the stabs debugging format. * Questions:: Questions and anomalies * Stab Sections:: In some object file formats, stabs are in sections. -* Symbol Types Index:: Index of symbolic stab symbol type names. * GNU Free Documentation License:: The license for this documentation +* Symbol Types Index:: Index of symbolic stab symbol type names. @end menu @end ifnottex diff --git a/contrib/gdb-7/gdb/doublest.c b/contrib/gdb-7/gdb/doublest.c index c8c9e05932..9ddc7a63f7 100644 --- a/contrib/gdb-7/gdb/doublest.c +++ b/contrib/gdb-7/gdb/doublest.c @@ -1,7 +1,6 @@ /* Floating point routines for GDB, the GNU debugger. - Copyright (C) 1986, 1988-2001, 2003-2005, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -472,6 +471,28 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt, mant = frexp (dfrom, &exponent); #endif + if (exponent + fmt->exp_bias <= 0) + { + /* The value is too small to be expressed in the destination + type (not enough bits in the exponent. Treat as 0. */ + put_field (uto, order, fmt->totalsize, fmt->exp_start, + fmt->exp_len, 0); + put_field (uto, order, fmt->totalsize, fmt->man_start, + fmt->man_len, 0); + goto finalize_byteorder; + } + + if (exponent + fmt->exp_bias >= (1 << fmt->exp_len)) + { + /* The value is too large to fit into the destination. + Treat as infinity. */ + put_field (uto, order, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + put_field (uto, order, fmt->totalsize, fmt->man_start, + fmt->man_len, 0); + goto finalize_byteorder; + } + put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len, exponent + fmt->exp_bias - 1); diff --git a/contrib/gdb-7/gdb/doublest.h b/contrib/gdb-7/gdb/doublest.h index cb22d62191..fad77346a4 100644 --- a/contrib/gdb-7/gdb/doublest.h +++ b/contrib/gdb-7/gdb/doublest.h @@ -1,7 +1,6 @@ /* Floating point definitions for GDB. - Copyright (C) 1986, 1988-2001, 2003, 2005-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/dummy-frame.c b/contrib/gdb-7/gdb/dummy-frame.c index 4a42a76b25..390a6d86bd 100644 --- a/contrib/gdb-7/gdb/dummy-frame.c +++ b/contrib/gdb-7/gdb/dummy-frame.c @@ -1,6 +1,6 @@ /* Code dealing with dummy stack frames, for GDB, the GNU debugger. - Copyright (C) 1986-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -29,6 +29,7 @@ #include "gdbcmd.h" #include "gdb_string.h" #include "observer.h" +#include "gdbthread.h" /* Dummy frame. This saves the processor state just prior to setting up the inferior function call. Older targets save the registers @@ -46,40 +47,6 @@ struct dummy_frame static struct dummy_frame *dummy_frame_stack = NULL; -/* Function: deprecated_pc_in_call_dummy (pc) - - Return non-zero if the PC falls in a dummy frame created by gdb for - an inferior call. The code below which allows gdbarch_decr_pc_after_break - is for infrun.c, which may give the function a PC without that - subtracted out. - - FIXME: cagney/2002-11-23: This is silly. Surely "infrun.c" can - figure out what the real PC (as in the resume address) is BEFORE - calling this function. - - NOTE: cagney/2004-08-02: I'm pretty sure that, with the introduction of - infrun.c:adjust_pc_after_break (thanks), this function is now - always called with a correctly adjusted PC! - - NOTE: cagney/2004-08-02: Code should not need to call this. */ - -int -deprecated_pc_in_call_dummy (struct gdbarch *gdbarch, CORE_ADDR pc) -{ - struct dummy_frame *dummyframe; - - for (dummyframe = dummy_frame_stack; - dummyframe != NULL; - dummyframe = dummyframe->next) - { - if ((pc >= dummyframe->id.code_addr) - && (pc <= dummyframe->id.code_addr - + gdbarch_decr_pc_after_break (gdbarch))) - return 1; - } - return 0; -} - /* Push the caller's state, along with the dummy frame info, onto the dummy-frame stack. */ @@ -108,19 +75,44 @@ remove_dummy_frame (struct dummy_frame **dummy_ptr) xfree (dummy); } +/* Delete any breakpoint B which is a momentary breakpoint for return from + inferior call matching DUMMY_VOIDP. */ + +static int +pop_dummy_frame_bpt (struct breakpoint *b, void *dummy_voidp) +{ + struct dummy_frame *dummy = dummy_voidp; + + if (b->thread == pid_to_thread_id (inferior_ptid) + && b->disposition == disp_del && frame_id_eq (b->frame_id, dummy->id)) + { + while (b->related_breakpoint != b) + delete_breakpoint (b->related_breakpoint); + + delete_breakpoint (b); + + /* Stop the traversal. */ + return 1; + } + + /* Continue the traversal. */ + return 0; +} + /* Pop *DUMMY_PTR, restoring program state to that before the frame was created. */ static void pop_dummy_frame (struct dummy_frame **dummy_ptr) { - struct dummy_frame *dummy; + struct dummy_frame *dummy = *dummy_ptr; + + restore_infcall_suspend_state (dummy->caller_state); - restore_infcall_suspend_state ((*dummy_ptr)->caller_state); + iterate_over_breakpoints (pop_dummy_frame_bpt, dummy); /* restore_infcall_control_state frees inf_state, all that remains is to pop *dummy_ptr. */ - dummy = *dummy_ptr; *dummy_ptr = dummy->next; xfree (dummy); @@ -166,9 +158,22 @@ dummy_frame_pop (struct frame_id dummy_id) pop_dummy_frame (dp); } -/* There may be stale dummy frames, perhaps left over from when a longjump took - us out of a function that was called by the debugger. Clean them up at - least once whenever we start a new inferior. */ +/* Drop dummy frame DUMMY_ID. Do nothing if it is not found. Do not restore + its state into inferior, just free its memory. */ + +void +dummy_frame_discard (struct frame_id dummy_id) +{ + struct dummy_frame **dp; + + dp = lookup_dummy_frame (dummy_id); + if (dp) + remove_dummy_frame (dp); +} + +/* There may be stale dummy frames, perhaps left over from when an uncaught + longjmp took us out of a function that was called by the debugger. Clean + them up at least once whenever we start a new inferior. */ static void cleanup_dummy_frames (struct target_ops *target, int from_tty) diff --git a/contrib/gdb-7/gdb/dummy-frame.h b/contrib/gdb-7/gdb/dummy-frame.h index a921e92bd5..f12f2cc085 100644 --- a/contrib/gdb-7/gdb/dummy-frame.h +++ b/contrib/gdb-7/gdb/dummy-frame.h @@ -1,6 +1,6 @@ /* Code dealing with dummy stack frames, for GDB, the GNU debugger. - Copyright (C) 2002, 2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -52,6 +52,8 @@ extern void dummy_frame_push (struct infcall_suspend_state *caller_state, extern void dummy_frame_pop (struct frame_id dummy_id); +extern void dummy_frame_discard (struct frame_id dummy_id); + /* If the PC falls in a dummy frame, return a dummy frame unwinder. */ diff --git a/contrib/gdb-7/gdb/dwarf2-frame-tailcall.c b/contrib/gdb-7/gdb/dwarf2-frame-tailcall.c index 912cdf4ac9..b82a0517dc 100644 --- a/contrib/gdb-7/gdb/dwarf2-frame-tailcall.c +++ b/contrib/gdb-7/gdb/dwarf2-frame-tailcall.c @@ -1,6 +1,6 @@ /* Virtual tail call frames unwinder for GDB. - Copyright (C) 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -223,9 +223,9 @@ tailcall_frame_this_id (struct frame_info *this_frame, void **this_cache, *this_id = get_frame_id (next_frame); (*this_id).code_addr = get_frame_pc (this_frame); (*this_id).code_addr_p = 1; - (*this_id).inline_depth = (cache->chain_levels - - existing_next_levels (this_frame, cache)); - gdb_assert ((*this_id).inline_depth > 0); + (*this_id).artificial_depth = (cache->chain_levels + - existing_next_levels (this_frame, cache)); + gdb_assert ((*this_id).artificial_depth > 0); } /* Find PC to be unwound from THIS_FRAME. THIS_FRAME must be a part of @@ -236,7 +236,6 @@ pretend_pc (struct frame_info *this_frame, struct tailcall_cache *cache) { int next_levels = existing_next_levels (this_frame, cache); struct call_site_chain *chain = cache->chain; - int caller_no; gdb_assert (chain != NULL); @@ -367,16 +366,17 @@ dwarf2_tailcall_sniffer_first (struct frame_info *this_frame, { CORE_ADDR prev_pc = 0, prev_sp = 0; /* GCC warning. */ int prev_sp_p = 0; - CORE_ADDR this_pc, pc; + CORE_ADDR this_pc; struct gdbarch *prev_gdbarch; struct call_site_chain *chain = NULL; - struct frame_info *fi; struct tailcall_cache *cache; volatile struct gdb_exception except; gdb_assert (*tailcall_cachep == NULL); - this_pc = get_frame_pc (this_frame); + /* PC may be after the function if THIS_FRAME calls noreturn function, + get_frame_address_in_block will decrease it by 1 in such case. */ + this_pc = get_frame_address_in_block (this_frame); /* Catch any unwinding errors. */ TRY_CATCH (except, RETURN_MASK_ERROR) diff --git a/contrib/gdb-7/gdb/dwarf2-frame-tailcall.h b/contrib/gdb-7/gdb/dwarf2-frame-tailcall.h index c5c88045f7..f9a4b9fd89 100644 --- a/contrib/gdb-7/gdb/dwarf2-frame-tailcall.h +++ b/contrib/gdb-7/gdb/dwarf2-frame-tailcall.h @@ -1,6 +1,6 @@ /* Definitions for virtual tail call frames unwinder for GDB. - Copyright (C) 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/dwarf2-frame.c b/contrib/gdb-7/gdb/dwarf2-frame.c index 88aa338919..ec4edfaaf3 100644 --- a/contrib/gdb-7/gdb/dwarf2-frame.c +++ b/contrib/gdb-7/gdb/dwarf2-frame.c @@ -1,6 +1,6 @@ /* Frame unwinder for frames with DWARF Call Frame Information. - Copyright (C) 2003-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. Contributed by Mark Kettenis. @@ -68,8 +68,8 @@ struct dwarf2_cie ULONGEST return_address_register; /* Instruction sequence to initialize a register set. */ - gdb_byte *initial_instructions; - gdb_byte *end; + const gdb_byte *initial_instructions; + const gdb_byte *end; /* Saved augmentation, in case it's needed later. */ char *augmentation; @@ -116,8 +116,8 @@ struct dwarf2_fde CORE_ADDR address_range; /* Instruction sequence. */ - gdb_byte *instructions; - gdb_byte *end; + const gdb_byte *instructions; + const gdb_byte *end; /* True if this FDE is read from a .eh_frame instead of a .debug_frame section. */ @@ -354,7 +354,8 @@ static const struct dwarf_expr_context_funcs dwarf2_frame_ctx_funcs = ctx_no_get_tls_address, ctx_no_dwarf_call, ctx_no_get_base_type, - ctx_no_push_dwarf_reg_entry_value + ctx_no_push_dwarf_reg_entry_value, + ctx_no_get_addr_index }; static CORE_ADDR @@ -415,8 +416,8 @@ execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr, while (insn_ptr < insn_end && fs->pc <= pc) { gdb_byte insn = *insn_ptr++; - ULONGEST utmp, reg; - LONGEST offset; + uint64_t utmp, reg; + int64_t offset; if ((insn & 0xc0) == DW_CFA_advance_loc) fs->pc += (insn & 0x3f) * fs->code_align; @@ -424,7 +425,7 @@ execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr, { reg = insn & 0x3f; reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); offset = utmp * fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET; @@ -466,9 +467,9 @@ execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr, break; case DW_CFA_offset_extended: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); offset = utmp * fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET; @@ -476,28 +477,28 @@ execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr, break; case DW_CFA_restore_extended: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); dwarf2_restore_rule (gdbarch, reg, fs, eh_frame_p); break; case DW_CFA_undefined: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNDEFINED; break; case DW_CFA_same_value: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAME_VALUE; break; case DW_CFA_register: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); utmp = dwarf2_frame_adjust_regnum (gdbarch, utmp, eh_frame_p); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG; @@ -535,8 +536,9 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_def_cfa: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->regs.cfa_reg); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); + fs->regs.cfa_reg = reg; + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); if (fs->armcc_cfa_offsets_sf) utmp *= fs->data_align; @@ -546,15 +548,14 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_def_cfa_register: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->regs.cfa_reg); - fs->regs.cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, - fs->regs.cfa_reg, + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); + fs->regs.cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); fs->regs.cfa_how = CFA_REG_OFFSET; break; case DW_CFA_def_cfa_offset: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); if (fs->armcc_cfa_offsets_sf) utmp *= fs->data_align; @@ -567,18 +568,18 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_def_cfa_expression: - insn_ptr = read_uleb128 (insn_ptr, insn_end, - &fs->regs.cfa_exp_len); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); + fs->regs.cfa_exp_len = utmp; fs->regs.cfa_exp = insn_ptr; fs->regs.cfa_how = CFA_EXP; insn_ptr += fs->regs.cfa_exp_len; break; case DW_CFA_expression: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); fs->regs.reg[reg].loc.exp = insn_ptr; fs->regs.reg[reg].exp_len = utmp; fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_EXP; @@ -586,9 +587,9 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_offset_extended_sf: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); - insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); + insn_ptr = safe_read_sleb128 (insn_ptr, insn_end, &offset); offset *= fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET; @@ -596,27 +597,27 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_val_offset: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); offset = utmp * fs->data_align; fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_OFFSET; fs->regs.reg[reg].loc.offset = offset; break; case DW_CFA_val_offset_sf: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); + insn_ptr = safe_read_sleb128 (insn_ptr, insn_end, &offset); offset *= fs->data_align; fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_OFFSET; fs->regs.reg[reg].loc.offset = offset; break; case DW_CFA_val_expression: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); fs->regs.reg[reg].loc.exp = insn_ptr; fs->regs.reg[reg].exp_len = utmp; fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_EXP; @@ -624,17 +625,16 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_def_cfa_sf: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->regs.cfa_reg); - fs->regs.cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, - fs->regs.cfa_reg, + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); + fs->regs.cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); - insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); + insn_ptr = safe_read_sleb128 (insn_ptr, insn_end, &offset); fs->regs.cfa_offset = offset * fs->data_align; fs->regs.cfa_how = CFA_REG_OFFSET; break; case DW_CFA_def_cfa_offset_sf: - insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); + insn_ptr = safe_read_sleb128 (insn_ptr, insn_end, &offset); fs->regs.cfa_offset = offset * fs->data_align; /* cfa_how deliberately not set. */ break; @@ -666,13 +666,13 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), case DW_CFA_GNU_args_size: /* Ignored. */ - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); break; case DW_CFA_GNU_negative_offset_extended: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &offset); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &offset); offset *= fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET; @@ -888,10 +888,8 @@ dwarf2_compile_cfa_to_ax (struct agent_expr *expr, struct axs_value *loc, CORE_ADDR pc, struct dwarf2_per_cu_data *data) { - const int num_regs = gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch); struct dwarf2_fde *fde; - CORE_ADDR text_offset, cfa; + CORE_ADDR text_offset; struct dwarf2_frame_state fs; int addr_size; @@ -994,10 +992,20 @@ struct dwarf2_frame_cache void *tailcall_cache; }; +/* A cleanup that sets a pointer to NULL. */ + +static void +clear_pointer_cleanup (void *arg) +{ + void **ptr = arg; + + *ptr = NULL; +} + static struct dwarf2_frame_cache * dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) { - struct cleanup *old_chain; + struct cleanup *reset_cache_cleanup, *old_chain; struct gdbarch *gdbarch = get_frame_arch (this_frame); const int num_regs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); @@ -1017,6 +1025,7 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) cache = FRAME_OBSTACK_ZALLOC (struct dwarf2_frame_cache); cache->reg = FRAME_OBSTACK_CALLOC (num_regs, struct dwarf2_frame_state_reg); *this_cache = cache; + reset_cache_cleanup = make_cleanup (clear_pointer_cleanup, this_cache); /* Allocate and initialize the frame state. */ fs = XZALLOC (struct dwarf2_frame_state); @@ -1054,7 +1063,8 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) /* First decode all the insns in the CIE. */ execute_cfa_program (fde, fde->cie->initial_instructions, - fde->cie->end, gdbarch, get_frame_pc (this_frame), fs); + fde->cie->end, gdbarch, + get_frame_address_in_block (this_frame), fs); /* Save the initialized register set. */ fs->initial = fs->regs; @@ -1079,7 +1089,7 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) /* Then decode the insns in the FDE up to our target PC. */ execute_cfa_program (fde, instr, fde->end, gdbarch, - get_frame_pc (this_frame), fs); + get_frame_address_in_block (this_frame), fs); TRY_CATCH (ex, RETURN_MASK_ERROR) { @@ -1110,6 +1120,8 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) if (ex.error == NOT_AVAILABLE_ERROR) { cache->unavailable_retaddr = 1; + do_cleanups (old_chain); + discard_cleanups (reset_cache_cleanup); return cache; } @@ -1225,6 +1237,7 @@ incomplete CFI data; unspecified registers (e.g., %s) at %s"), (entry_cfa_sp_offset_p ? &entry_cfa_sp_offset : NULL)); + discard_cleanups (reset_cache_cleanup); return cache; } @@ -1490,88 +1503,36 @@ dwarf2_frame_cfa (struct frame_info *this_frame) if (!frame_unwinder_is (this_frame, &dwarf2_frame_unwind) && !frame_unwinder_is (this_frame, &dwarf2_tailcall_frame_unwind)) error (_("can't compute CFA for this frame")); + if (get_frame_unwind_stop_reason (this_frame) == UNWIND_UNAVAILABLE) + throw_error (NOT_AVAILABLE_ERROR, + _("can't compute CFA for this frame: " + "required registers or memory are unavailable")); return get_frame_base (this_frame); } const struct objfile_data *dwarf2_frame_objfile_data; static unsigned int -read_1_byte (bfd *abfd, gdb_byte *buf) +read_1_byte (bfd *abfd, const gdb_byte *buf) { return bfd_get_8 (abfd, buf); } static unsigned int -read_4_bytes (bfd *abfd, gdb_byte *buf) +read_4_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_32 (abfd, buf); } static ULONGEST -read_8_bytes (bfd *abfd, gdb_byte *buf) +read_8_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_64 (abfd, buf); } static ULONGEST -read_unsigned_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) -{ - ULONGEST result; - unsigned int num_read; - int shift; - gdb_byte byte; - - result = 0; - shift = 0; - num_read = 0; - - do - { - byte = bfd_get_8 (abfd, (bfd_byte *) buf); - buf++; - num_read++; - result |= ((byte & 0x7f) << shift); - shift += 7; - } - while (byte & 0x80); - - *bytes_read_ptr = num_read; - - return result; -} - -static LONGEST -read_signed_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) -{ - LONGEST result; - int shift; - unsigned int num_read; - gdb_byte byte; - - result = 0; - shift = 0; - num_read = 0; - - do - { - byte = bfd_get_8 (abfd, (bfd_byte *) buf); - buf++; - num_read++; - result |= ((byte & 0x7f) << shift); - shift += 7; - } - while (byte & 0x80); - - if (shift < 8 * sizeof (result) && (byte & 0x40)) - result |= -(((LONGEST)1) << shift); - - *bytes_read_ptr = num_read; - - return result; -} - -static ULONGEST -read_initial_length (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) +read_initial_length (bfd *abfd, const gdb_byte *buf, + unsigned int *bytes_read_ptr) { LONGEST result; @@ -1680,10 +1641,10 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, { case DW_EH_PE_uleb128: { - ULONGEST value; + uint64_t value; const gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7; - *bytes_read_ptr += read_uleb128 (buf, end_buf, &value) - buf; + *bytes_read_ptr += safe_read_uleb128 (buf, end_buf, &value) - buf; return base + value; } case DW_EH_PE_udata2: @@ -1697,10 +1658,10 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, return (base + bfd_get_64 (unit->abfd, (bfd_byte *) buf)); case DW_EH_PE_sleb128: { - LONGEST value; + int64_t value; const gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7; - *bytes_read_ptr += read_sleb128 (buf, end_buf, &value) - buf; + *bytes_read_ptr += safe_read_sleb128 (buf, end_buf, &value) - buf; return base + value; } case DW_EH_PE_sdata2: @@ -1842,11 +1803,7 @@ add_fde (struct dwarf2_fde_table *fde_table, struct dwarf2_fde *fde) fde_table->entries[fde_table->num_entries - 1] = fde; } -#ifdef CC_HAS_LONG_LONG #define DW64_CIE_ID 0xffffffffffffffffULL -#else -#define DW64_CIE_ID ~0 -#endif /* Defines the type of eh_frames that are expected to be decoded: CIE, FDE or any of them. */ @@ -1858,28 +1815,32 @@ enum eh_frame_type EH_CIE_OR_FDE_TYPE_ID = EH_CIE_TYPE_ID | EH_FDE_TYPE_ID }; -static gdb_byte *decode_frame_entry (struct comp_unit *unit, gdb_byte *start, - int eh_frame_p, - struct dwarf2_cie_table *cie_table, - struct dwarf2_fde_table *fde_table, - enum eh_frame_type entry_type); +static const gdb_byte *decode_frame_entry (struct comp_unit *unit, + const gdb_byte *start, + int eh_frame_p, + struct dwarf2_cie_table *cie_table, + struct dwarf2_fde_table *fde_table, + enum eh_frame_type entry_type); /* Decode the next CIE or FDE, entry_type specifies the expected type. Return NULL if invalid input, otherwise the next byte to be processed. */ -static gdb_byte * -decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, +static const gdb_byte * +decode_frame_entry_1 (struct comp_unit *unit, const gdb_byte *start, + int eh_frame_p, struct dwarf2_cie_table *cie_table, struct dwarf2_fde_table *fde_table, enum eh_frame_type entry_type) { struct gdbarch *gdbarch = get_objfile_arch (unit->objfile); - gdb_byte *buf, *end; + const gdb_byte *buf, *end; LONGEST length; unsigned int bytes_read; int dwarf64_p; ULONGEST cie_id; ULONGEST cie_pointer; + int64_t sleb128; + uint64_t uleb128; buf = start; length = read_initial_length (unit->abfd, buf, &bytes_read); @@ -1995,37 +1956,41 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, else cie->ptr_size = cie->addr_size; - cie->code_alignment_factor = - read_unsigned_leb128 (unit->abfd, buf, &bytes_read); - buf += bytes_read; + buf = gdb_read_uleb128 (buf, end, &uleb128); + if (buf == NULL) + return NULL; + cie->code_alignment_factor = uleb128; - cie->data_alignment_factor = - read_signed_leb128 (unit->abfd, buf, &bytes_read); - buf += bytes_read; + buf = gdb_read_sleb128 (buf, end, &sleb128); + if (buf == NULL) + return NULL; + cie->data_alignment_factor = sleb128; if (cie_version == 1) { cie->return_address_register = read_1_byte (unit->abfd, buf); - bytes_read = 1; + ++buf; } else - cie->return_address_register = read_unsigned_leb128 (unit->abfd, buf, - &bytes_read); + { + buf = gdb_read_uleb128 (buf, end, &uleb128); + if (buf == NULL) + return NULL; + cie->return_address_register = uleb128; + } + cie->return_address_register = dwarf2_frame_adjust_regnum (gdbarch, cie->return_address_register, eh_frame_p); - buf += bytes_read; - cie->saw_z_augmentation = (*augmentation == 'z'); if (cie->saw_z_augmentation) { - ULONGEST length; + uint64_t length; - length = read_unsigned_leb128 (unit->abfd, buf, &bytes_read); - buf += bytes_read; - if (buf > end) + buf = gdb_read_uleb128 (buf, end, &length); + if (buf == NULL) return NULL; cie->initial_instructions = buf + length; augmentation++; @@ -2139,10 +2104,12 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, can skip the whole thing. */ if (fde->cie->saw_z_augmentation) { - ULONGEST length; + uint64_t length; - length = read_unsigned_leb128 (unit->abfd, buf, &bytes_read); - buf += bytes_read + length; + buf = gdb_read_uleb128 (buf, end, &length); + if (buf == NULL) + return NULL; + buf += length; if (buf > end) return NULL; } @@ -2161,14 +2128,15 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, /* Read a CIE or FDE in BUF and decode it. Entry_type specifies whether we expect an FDE or a CIE. */ -static gdb_byte * -decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, +static const gdb_byte * +decode_frame_entry (struct comp_unit *unit, const gdb_byte *start, + int eh_frame_p, struct dwarf2_cie_table *cie_table, struct dwarf2_fde_table *fde_table, enum eh_frame_type entry_type) { enum { NONE, ALIGN4, ALIGN8, FAIL } workaround = NONE; - gdb_byte *ret; + const gdb_byte *ret; ptrdiff_t start_offset; while (1) @@ -2280,7 +2248,7 @@ void dwarf2_build_frame_info (struct objfile *objfile) { struct comp_unit *unit; - gdb_byte *frame_ptr; + const gdb_byte *frame_ptr; struct dwarf2_cie_table cie_table; struct dwarf2_fde_table fde_table; struct dwarf2_fde_table *fde_table2; diff --git a/contrib/gdb-7/gdb/dwarf2-frame.h b/contrib/gdb-7/gdb/dwarf2-frame.h index 33f7bf7942..6a7ca34ba5 100644 --- a/contrib/gdb-7/gdb/dwarf2-frame.h +++ b/contrib/gdb-7/gdb/dwarf2-frame.h @@ -1,6 +1,6 @@ /* Frame unwinder for frames with DWARF Call Frame Information. - Copyright (C) 2003-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. Contributed by Mark Kettenis. diff --git a/contrib/gdb-7/gdb/dwarf2expr.c b/contrib/gdb-7/gdb/dwarf2expr.c index 222fcc302b..752d782601 100644 --- a/contrib/gdb-7/gdb/dwarf2expr.c +++ b/contrib/gdb-7/gdb/dwarf2expr.c @@ -1,7 +1,6 @@ /* DWARF 2 Expression Evaluator. - Copyright (C) 2001-2003, 2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. Contributed by Daniel Berlin (dan@dberlin.org) @@ -342,7 +341,7 @@ add_piece (struct dwarf_expr_context *ctx, ULONGEST size, ULONGEST offset) } else if (p->location == DWARF_VALUE_IMPLICIT_POINTER) { - p->v.ptr.die = ctx->len; + p->v.ptr.die.sect_off = ctx->len; p->v.ptr.offset = value_as_long (dwarf_expr_fetch (ctx, 0)); } else if (p->location == DWARF_VALUE_REGISTER) @@ -369,60 +368,36 @@ dwarf_expr_eval (struct dwarf_expr_context *ctx, const gdb_byte *addr, gdb_assert (ctx->recursion_depth == old_recursion_depth); } -/* Decode the unsigned LEB128 constant at BUF into the variable pointed to - by R, and return the new value of BUF. Verify that it doesn't extend - past BUF_END. R can be NULL, the constant is then only skipped. */ +/* Helper to read a uleb128 value or throw an error. */ const gdb_byte * -read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, ULONGEST * r) +safe_read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, + uint64_t *r) { - unsigned shift = 0; - ULONGEST result = 0; - gdb_byte byte; - - while (1) - { - if (buf >= buf_end) - error (_("read_uleb128: Corrupted DWARF expression.")); - - byte = *buf++; - result |= ((ULONGEST) (byte & 0x7f)) << shift; - if ((byte & 0x80) == 0) - break; - shift += 7; - } - if (r) - *r = result; + buf = gdb_read_uleb128 (buf, buf_end, r); + if (buf == NULL) + error (_("DWARF expression error: ran off end of buffer reading uleb128 value")); return buf; } -/* Decode the signed LEB128 constant at BUF into the variable pointed to - by R, and return the new value of BUF. Verify that it doesn't extend - past BUF_END. R can be NULL, the constant is then only skipped. */ +/* Helper to read a sleb128 value or throw an error. */ const gdb_byte * -read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, LONGEST * r) +safe_read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, + int64_t *r) { - unsigned shift = 0; - LONGEST result = 0; - gdb_byte byte; - - while (1) - { - if (buf >= buf_end) - error (_("read_sleb128: Corrupted DWARF expression.")); - - byte = *buf++; - result |= ((ULONGEST) (byte & 0x7f)) << shift; - shift += 7; - if ((byte & 0x80) == 0) - break; - } - if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0) - result |= -(((LONGEST) 1) << shift); + buf = gdb_read_sleb128 (buf, buf_end, r); + if (buf == NULL) + error (_("DWARF expression error: ran off end of buffer reading sleb128 value")); + return buf; +} - if (r) - *r = result; +const gdb_byte * +safe_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end) +{ + buf = gdb_skip_leb128 (buf, buf_end); + if (buf == NULL) + error (_("DWARF expression error: ran off end of buffer reading leb128 value")); return buf; } @@ -464,7 +439,7 @@ base_types_equal_p (struct type *t1, struct type *t2) size. */ static struct type * -dwarf_get_base_type (struct dwarf_expr_context *ctx, ULONGEST die, int size) +dwarf_get_base_type (struct dwarf_expr_context *ctx, cu_offset die, int size) { struct type *result; @@ -489,7 +464,7 @@ dwarf_get_base_type (struct dwarf_expr_context *ctx, ULONGEST die, int size) int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end) { - ULONGEST dwarf_reg; + uint64_t dwarf_reg; if (buf_end <= buf) return -1; @@ -503,13 +478,19 @@ dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end) if (*buf == DW_OP_GNU_regval_type) { buf++; - buf = read_uleb128 (buf, buf_end, &dwarf_reg); - buf = read_uleb128 (buf, buf_end, NULL); + buf = gdb_read_uleb128 (buf, buf_end, &dwarf_reg); + if (buf == NULL) + return -1; + buf = gdb_skip_leb128 (buf, buf_end); + if (buf == NULL) + return -1; } else if (*buf == DW_OP_regx) { buf++; - buf = read_uleb128 (buf, buf_end, &dwarf_reg); + buf = gdb_read_uleb128 (buf, buf_end, &dwarf_reg); + if (buf == NULL) + return -1; } else return -1; @@ -527,31 +508,35 @@ int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end, CORE_ADDR *deref_size_return) { - ULONGEST dwarf_reg; - LONGEST offset; + uint64_t dwarf_reg; + int64_t offset; if (buf_end <= buf) return -1; + if (*buf >= DW_OP_breg0 && *buf <= DW_OP_breg31) { dwarf_reg = *buf - DW_OP_breg0; buf++; + if (buf >= buf_end) + return -1; } else if (*buf == DW_OP_bregx) { buf++; - buf = read_uleb128 (buf, buf_end, &dwarf_reg); + buf = gdb_read_uleb128 (buf, buf_end, &dwarf_reg); + if (buf == NULL) + return -1; if ((int) dwarf_reg != dwarf_reg) return -1; } else return -1; - buf = read_sleb128 (buf, buf_end, &offset); - if (offset != 0) + buf = gdb_read_sleb128 (buf, buf_end, &offset); + if (buf == NULL) return -1; - - if (buf >= buf_end) + if (offset != 0) return -1; if (*buf == DW_OP_deref) @@ -582,7 +567,7 @@ int dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end, CORE_ADDR *fb_offset_return) { - LONGEST fb_offset; + int64_t fb_offset; if (buf_end <= buf) return 0; @@ -591,7 +576,9 @@ dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end, return 0; buf++; - buf = read_sleb128 (buf, buf_end, &fb_offset); + buf = gdb_read_sleb128 (buf, buf_end, &fb_offset); + if (buf == NULL) + return 0; *fb_offset_return = fb_offset; if (buf != buf_end || fb_offset != (LONGEST) *fb_offset_return) return 0; @@ -607,8 +594,8 @@ int dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf, const gdb_byte *buf_end, CORE_ADDR *sp_offset_return) { - ULONGEST dwarf_reg; - LONGEST sp_offset; + uint64_t dwarf_reg; + int64_t sp_offset; if (buf_end <= buf) return 0; @@ -622,14 +609,18 @@ dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf, if (*buf != DW_OP_bregx) return 0; buf++; - buf = read_uleb128 (buf, buf_end, &dwarf_reg); + buf = gdb_read_uleb128 (buf, buf_end, &dwarf_reg); + if (buf == NULL) + return 0; } if (gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_reg) != gdbarch_sp_regnum (gdbarch)) return 0; - buf = read_sleb128 (buf, buf_end, &sp_offset); + buf = gdb_read_sleb128 (buf, buf_end, &sp_offset); + if (buf == NULL) + return 0; *sp_offset_return = sp_offset; if (buf != buf_end || sp_offset != (LONGEST) *sp_offset_return) return 0; @@ -673,8 +664,8 @@ execute_stack_op (struct dwarf_expr_context *ctx, This is just an optimization, so it's always ok to punt and leave this as 0. */ int in_stack_memory = 0; - ULONGEST uoffset, reg; - LONGEST offset; + uint64_t uoffset, reg; + int64_t offset; struct value *result_val = NULL; /* The DWARF expression might have a bug causing an infinite @@ -732,6 +723,18 @@ execute_stack_op (struct dwarf_expr_context *ctx, result_val = value_from_ulongest (address_type, result); break; + case DW_OP_GNU_addr_index: + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset); + result = (ctx->funcs->get_addr_index) (ctx->baton, uoffset); + result += ctx->offset; + result_val = value_from_ulongest (address_type, result); + break; + case DW_OP_GNU_const_index: + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset); + result = (ctx->funcs->get_addr_index) (ctx->baton, uoffset); + result_val = value_from_ulongest (address_type, result); + break; + case DW_OP_const1u: result = extract_unsigned_integer (op_ptr, 1, byte_order); result_val = value_from_ulongest (address_type, result); @@ -773,12 +776,12 @@ execute_stack_op (struct dwarf_expr_context *ctx, op_ptr += 8; break; case DW_OP_constu: - op_ptr = read_uleb128 (op_ptr, op_end, &uoffset); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset); result = uoffset; result_val = value_from_ulongest (address_type, result); break; case DW_OP_consts: - op_ptr = read_sleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset); result = offset; result_val = value_from_ulongest (address_type, result); break; @@ -831,7 +834,7 @@ execute_stack_op (struct dwarf_expr_context *ctx, break; case DW_OP_regx: - op_ptr = read_uleb128 (op_ptr, op_end, ®); + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®); dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx"); result = reg; @@ -841,9 +844,9 @@ execute_stack_op (struct dwarf_expr_context *ctx, case DW_OP_implicit_value: { - ULONGEST len; + uint64_t len; - op_ptr = read_uleb128 (op_ptr, op_end, &len); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &len); if (op_ptr + len > op_end) error (_("DW_OP_implicit_value: too few bytes available.")); ctx->len = len; @@ -862,20 +865,19 @@ execute_stack_op (struct dwarf_expr_context *ctx, case DW_OP_GNU_implicit_pointer: { - ULONGEST die; - LONGEST len; + int64_t len; if (ctx->ref_addr_size == -1) error (_("DWARF-2 expression error: DW_OP_GNU_implicit_pointer " "is not allowed in frame context")); - /* The referred-to DIE. */ + /* The referred-to DIE of sect_offset kind. */ ctx->len = extract_unsigned_integer (op_ptr, ctx->ref_addr_size, byte_order); op_ptr += ctx->ref_addr_size; /* The byte offset into the data. */ - op_ptr = read_sleb128 (op_ptr, op_end, &len); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &len); result = (ULONGEST) len; result_val = value_from_ulongest (address_type, result); @@ -918,7 +920,7 @@ execute_stack_op (struct dwarf_expr_context *ctx, case DW_OP_breg30: case DW_OP_breg31: { - op_ptr = read_sleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset); result = (ctx->funcs->read_reg) (ctx->baton, op - DW_OP_breg0); result += offset; result_val = value_from_ulongest (address_type, result); @@ -926,8 +928,8 @@ execute_stack_op (struct dwarf_expr_context *ctx, break; case DW_OP_bregx: { - op_ptr = read_uleb128 (op_ptr, op_end, ®); - op_ptr = read_sleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset); result = (ctx->funcs->read_reg) (ctx->baton, reg); result += offset; result_val = value_from_ulongest (address_type, result); @@ -939,7 +941,7 @@ execute_stack_op (struct dwarf_expr_context *ctx, size_t datalen; unsigned int before_stack_len; - op_ptr = read_sleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset); /* Rather than create a whole new context, we simply record the stack length before execution, then reset it afterwards, effectively erasing whatever the recursive @@ -1031,9 +1033,10 @@ execute_stack_op (struct dwarf_expr_context *ctx, if (op == DW_OP_GNU_deref_type) { - ULONGEST type_die; + cu_offset type_die; - op_ptr = read_uleb128 (op_ptr, op_end, &type_die); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset); + type_die.cu_off = uoffset; type = dwarf_get_base_type (ctx, type_die, 0); } else @@ -1083,7 +1086,7 @@ execute_stack_op (struct dwarf_expr_context *ctx, case DW_OP_plus_uconst: dwarf_require_integral (value_type (result_val)); result = value_as_long (result_val); - op_ptr = read_uleb128 (op_ptr, op_end, ®); + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®); result += reg; result_val = value_from_ulongest (address_type, result); break; @@ -1293,10 +1296,10 @@ execute_stack_op (struct dwarf_expr_context *ctx, case DW_OP_piece: { - ULONGEST size; + uint64_t size; /* Record the piece. */ - op_ptr = read_uleb128 (op_ptr, op_end, &size); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &size); add_piece (ctx, 8 * size, 0); /* Pop off the address/regnum, and reset the location @@ -1310,11 +1313,11 @@ execute_stack_op (struct dwarf_expr_context *ctx, case DW_OP_bit_piece: { - ULONGEST size, offset; + uint64_t size, offset; /* Record the piece. */ - op_ptr = read_uleb128 (op_ptr, op_end, &size); - op_ptr = read_uleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &size); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &offset); add_piece (ctx, size, offset); /* Pop off the address/regnum, and reset the location @@ -1335,47 +1338,57 @@ execute_stack_op (struct dwarf_expr_context *ctx, goto no_push; case DW_OP_call2: - result = extract_unsigned_integer (op_ptr, 2, byte_order); - op_ptr += 2; - ctx->funcs->dwarf_call (ctx, result); + { + cu_offset offset; + + offset.cu_off = extract_unsigned_integer (op_ptr, 2, byte_order); + op_ptr += 2; + ctx->funcs->dwarf_call (ctx, offset); + } goto no_push; case DW_OP_call4: - result = extract_unsigned_integer (op_ptr, 4, byte_order); - op_ptr += 4; - ctx->funcs->dwarf_call (ctx, result); + { + cu_offset offset; + + offset.cu_off = extract_unsigned_integer (op_ptr, 4, byte_order); + op_ptr += 4; + ctx->funcs->dwarf_call (ctx, offset); + } goto no_push; case DW_OP_GNU_entry_value: { - ULONGEST len; - int dwarf_reg; + uint64_t len; CORE_ADDR deref_size; + union call_site_parameter_u kind_u; - op_ptr = read_uleb128 (op_ptr, op_end, &len); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &len); if (op_ptr + len > op_end) error (_("DW_OP_GNU_entry_value: too few bytes available.")); - dwarf_reg = dwarf_block_to_dwarf_reg (op_ptr, op_ptr + len); - if (dwarf_reg != -1) + kind_u.dwarf_reg = dwarf_block_to_dwarf_reg (op_ptr, op_ptr + len); + if (kind_u.dwarf_reg != -1) { op_ptr += len; - ctx->funcs->push_dwarf_reg_entry_value (ctx, dwarf_reg, - 0 /* unused */, + ctx->funcs->push_dwarf_reg_entry_value (ctx, + CALL_SITE_PARAMETER_DWARF_REG, + kind_u, -1 /* deref_size */); goto no_push; } - dwarf_reg = dwarf_block_to_dwarf_reg_deref (op_ptr, op_ptr + len, - &deref_size); - if (dwarf_reg != -1) + kind_u.dwarf_reg = dwarf_block_to_dwarf_reg_deref (op_ptr, + op_ptr + len, + &deref_size); + if (kind_u.dwarf_reg != -1) { if (deref_size == -1) deref_size = ctx->addr_size; op_ptr += len; - ctx->funcs->push_dwarf_reg_entry_value (ctx, dwarf_reg, - 0 /* unused */, - deref_size); + ctx->funcs->push_dwarf_reg_entry_value (ctx, + CALL_SITE_PARAMETER_DWARF_REG, + kind_u, deref_size); goto no_push; } @@ -1384,14 +1397,29 @@ execute_stack_op (struct dwarf_expr_context *ctx, "or for DW_OP_breg*(0)+DW_OP_deref*")); } + case DW_OP_GNU_parameter_ref: + { + union call_site_parameter_u kind_u; + + kind_u.param_offset.cu_off = extract_unsigned_integer (op_ptr, 4, + byte_order); + op_ptr += 4; + ctx->funcs->push_dwarf_reg_entry_value (ctx, + CALL_SITE_PARAMETER_PARAM_OFFSET, + kind_u, + -1 /* deref_size */); + } + goto no_push; + case DW_OP_GNU_const_type: { - ULONGEST type_die; + cu_offset type_die; int n; const gdb_byte *data; struct type *type; - op_ptr = read_uleb128 (op_ptr, op_end, &type_die); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset); + type_die.cu_off = uoffset; n = *op_ptr++; data = op_ptr; op_ptr += n; @@ -1403,11 +1431,12 @@ execute_stack_op (struct dwarf_expr_context *ctx, case DW_OP_GNU_regval_type: { - ULONGEST type_die; + cu_offset type_die; struct type *type; - op_ptr = read_uleb128 (op_ptr, op_end, ®); - op_ptr = read_uleb128 (op_ptr, op_end, &type_die); + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset); + type_die.cu_off = uoffset; type = dwarf_get_base_type (ctx, type_die, 0); result = (ctx->funcs->read_reg) (ctx->baton, reg); @@ -1420,12 +1449,13 @@ execute_stack_op (struct dwarf_expr_context *ctx, case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: { - ULONGEST type_die; + cu_offset type_die; struct type *type; - op_ptr = read_uleb128 (op_ptr, op_end, &type_die); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset); + type_die.cu_off = uoffset; - if (type_die == 0) + if (type_die.cu_off == 0) type = address_type; else type = dwarf_get_base_type (ctx, type_die, 0); @@ -1506,7 +1536,7 @@ ctx_no_get_tls_address (void *baton, CORE_ADDR offset) /* Stub dwarf_expr_context_funcs.dwarf_call implementation. */ void -ctx_no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset) +ctx_no_dwarf_call (struct dwarf_expr_context *ctx, cu_offset die_offset) { error (_("%s is invalid in this context"), "DW_OP_call*"); } @@ -1514,7 +1544,7 @@ ctx_no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset) /* Stub dwarf_expr_context_funcs.get_base_type implementation. */ struct type * -ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die) +ctx_no_get_base_type (struct dwarf_expr_context *ctx, cu_offset die) { error (_("Support for typed DWARF is not supported in this context")); } @@ -1524,13 +1554,25 @@ ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die) void ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, - int dwarf_reg, CORE_ADDR fb_offset, + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u, int deref_size) { internal_error (__FILE__, __LINE__, _("Support for DW_OP_GNU_entry_value is unimplemented")); } +/* Stub dwarf_expr_context_funcs.get_addr_index implementation. */ + +CORE_ADDR +ctx_no_get_addr_index (void *baton, unsigned int index) +{ + error (_("%s is invalid in this context"), "DW_OP_GNU_addr_index"); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_dwarf2expr; + void _initialize_dwarf2expr (void) { diff --git a/contrib/gdb-7/gdb/dwarf2expr.h b/contrib/gdb-7/gdb/dwarf2expr.h index fd70bf98a3..e85486a500 100644 --- a/contrib/gdb-7/gdb/dwarf2expr.h +++ b/contrib/gdb-7/gdb/dwarf2expr.h @@ -1,7 +1,6 @@ /* DWARF 2 Expression Evaluator. - Copyright (C) 2001-2003, 2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. Contributed by Daniel Berlin . @@ -23,6 +22,9 @@ #if !defined (DWARF2EXPR_H) #define DWARF2EXPR_H +#include "leb128.h" +#include "gdbtypes.h" + struct dwarf_expr_context; /* Virtual method table for struct dwarf_expr_context below. */ @@ -53,26 +55,28 @@ struct dwarf_expr_context_funcs /* Execute DW_AT_location expression for the DWARF expression subroutine in the DIE at DIE_OFFSET in the CU from CTX. Do not touch STACK while it being passed to and returned from the called DWARF subroutine. */ - void (*dwarf_call) (struct dwarf_expr_context *ctx, size_t die_offset); + void (*dwarf_call) (struct dwarf_expr_context *ctx, cu_offset die_offset); /* Return the base type given by the indicated DIE. This can throw an exception if the DIE is invalid or does not represent a base type. If can also be NULL in the special case where the callbacks are not performing evaluation, and thus it is meaningful to substitute a stub type of the correct size. */ - struct type *(*get_base_type) (struct dwarf_expr_context *ctx, size_t die); + struct type *(*get_base_type) (struct dwarf_expr_context *ctx, cu_offset die); /* Push on DWARF stack an entry evaluated for DW_TAG_GNU_call_site's - DWARF_REG/FB_OFFSET at the caller of specified BATON. If DWARF register - number DWARF_REG specifying the push_dwarf_reg_entry_value parameter is - not -1 FB_OFFSET is ignored. Otherwise FB_OFFSET specifies stack - parameter offset against caller's stack pointer (which equals the callee's - frame base). If DEREF_SIZE is not -1 then use - DW_AT_GNU_call_site_data_value instead of DW_AT_GNU_call_site_value. */ + parameter matching KIND and KIND_U at the caller of specified BATON. + If DEREF_SIZE is not -1 then use DW_AT_GNU_call_site_data_value instead of + DW_AT_GNU_call_site_value. */ void (*push_dwarf_reg_entry_value) (struct dwarf_expr_context *ctx, - int dwarf_reg, CORE_ADDR fb_offset, + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u, int deref_size); + /* Return the address indexed by DW_OP_GNU_addr_index. + This can throw an exception if the index is out of range. */ + CORE_ADDR (*get_addr_index) (void *baton, unsigned int index); + #if 0 /* Not yet implemented. */ @@ -140,7 +144,7 @@ struct dwarf_expr_context context and operations depending on DW_FORM_ref_addr are not allowed. */ int ref_addr_size; - /* Offset used to relocate DW_OP_addr argument. */ + /* Offset used to relocate DW_OP_addr and DW_OP_GNU_addr_index arguments. */ CORE_ADDR offset; /* An opaque argument provided by the caller, which will be passed @@ -160,7 +164,7 @@ struct dwarf_expr_context /* For DWARF_VALUE_LITERAL, the current literal value's length and data. For DWARF_VALUE_IMPLICIT_POINTER, LEN is the offset of the - target DIE. */ + target DIE of sect_offset kind. */ ULONGEST len; const gdb_byte *data; @@ -231,7 +235,7 @@ struct dwarf_expr_piece struct { /* The referent DIE from DW_OP_GNU_implicit_pointer. */ - ULONGEST die; + sect_offset die; /* The byte offset into the resulting data. */ LONGEST offset; } ptr; @@ -257,14 +261,6 @@ struct value *dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n); CORE_ADDR dwarf_expr_fetch_address (struct dwarf_expr_context *ctx, int n); int dwarf_expr_fetch_in_stack_memory (struct dwarf_expr_context *ctx, int n); - -const gdb_byte *read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, - ULONGEST * r); -const gdb_byte *read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, - LONGEST * r); - -const char *dwarf_stack_op_name (unsigned int); - void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *, const char *); @@ -275,11 +271,14 @@ void ctx_no_get_frame_base (void *baton, const gdb_byte **start, CORE_ADDR ctx_no_get_frame_cfa (void *baton); CORE_ADDR ctx_no_get_frame_pc (void *baton); CORE_ADDR ctx_no_get_tls_address (void *baton, CORE_ADDR offset); -void ctx_no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset); -struct type *ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die); +void ctx_no_dwarf_call (struct dwarf_expr_context *ctx, cu_offset die_offset); +struct type *ctx_no_get_base_type (struct dwarf_expr_context *ctx, + cu_offset die); void ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, - int dwarf_reg, CORE_ADDR fb_offset, + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u, int deref_size); +CORE_ADDR ctx_no_get_addr_index (void *baton, unsigned int index); int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end); @@ -294,4 +293,50 @@ int dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf, const gdb_byte *buf_end, CORE_ADDR *sp_offset_return); +/* Wrappers around the leb128 reader routines to simplify them for our + purposes. */ + +static inline const gdb_byte * +gdb_read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, + uint64_t *r) +{ + size_t bytes_read = read_uleb128_to_uint64 (buf, buf_end, r); + + if (bytes_read == 0) + return NULL; + return buf + bytes_read; +} + +static inline const gdb_byte * +gdb_read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, + int64_t *r) +{ + size_t bytes_read = read_sleb128_to_int64 (buf, buf_end, r); + + if (bytes_read == 0) + return NULL; + return buf + bytes_read; +} + +static inline const gdb_byte * +gdb_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end) +{ + size_t bytes_read = skip_leb128 (buf, buf_end); + + if (bytes_read == 0) + return NULL; + return buf + bytes_read; +} + +extern const gdb_byte *safe_read_uleb128 (const gdb_byte *buf, + const gdb_byte *buf_end, + uint64_t *r); + +extern const gdb_byte *safe_read_sleb128 (const gdb_byte *buf, + const gdb_byte *buf_end, + int64_t *r); + +extern const gdb_byte *safe_skip_leb128 (const gdb_byte *buf, + const gdb_byte *buf_end); + #endif /* dwarf2expr.h */ diff --git a/contrib/gdb-7/gdb/dwarf2loc.c b/contrib/gdb-7/gdb/dwarf2loc.c index 313df7b490..625d8592ad 100644 --- a/contrib/gdb-7/gdb/dwarf2loc.c +++ b/contrib/gdb-7/gdb/dwarf2loc.c @@ -1,6 +1,6 @@ /* DWARF 2 location expression support for GDB. - Copyright (C) 2003, 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. Contributed by Daniel Jacobowitz, MontaVista Software, Inc. @@ -42,6 +42,8 @@ #include "gdb_string.h" #include "gdb_assert.h" +DEF_VEC_I(int); + extern int dwarf2_always_disassemble; static void dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc, @@ -52,10 +54,143 @@ static const struct dwarf_expr_context_funcs dwarf_expr_ctx_funcs; static struct value *dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, const gdb_byte *data, - unsigned short size, - struct dwarf2_per_cu_data *per_cu, + size_t size, + struct dwarf2_per_cu_data *per_cu, LONGEST byte_offset); +/* Until these have formal names, we define these here. + ref: http://gcc.gnu.org/wiki/DebugFission + Each entry in .debug_loc.dwo begins with a byte that describes the entry, + and is then followed by data specific to that entry. */ + +enum debug_loc_kind +{ + /* Indicates the end of the list of entries. */ + DEBUG_LOC_END_OF_LIST = 0, + + /* This is followed by an unsigned LEB128 number that is an index into + .debug_addr and specifies the base address for all following entries. */ + DEBUG_LOC_BASE_ADDRESS = 1, + + /* This is followed by two unsigned LEB128 numbers that are indices into + .debug_addr and specify the beginning and ending addresses, and then + a normal location expression as in .debug_loc. */ + DEBUG_LOC_START_END = 2, + + /* This is followed by an unsigned LEB128 number that is an index into + .debug_addr and specifies the beginning address, and a 4 byte unsigned + number that specifies the length, and then a normal location expression + as in .debug_loc. */ + DEBUG_LOC_START_LENGTH = 3, + + /* An internal value indicating there is insufficient data. */ + DEBUG_LOC_BUFFER_OVERFLOW = -1, + + /* An internal value indicating an invalid kind of entry was found. */ + DEBUG_LOC_INVALID_ENTRY = -2 +}; + +/* Decode the addresses in a non-dwo .debug_loc entry. + A pointer to the next byte to examine is returned in *NEW_PTR. + The encoded low,high addresses are return in *LOW,*HIGH. + The result indicates the kind of entry found. */ + +static enum debug_loc_kind +decode_debug_loc_addresses (const gdb_byte *loc_ptr, const gdb_byte *buf_end, + const gdb_byte **new_ptr, + CORE_ADDR *low, CORE_ADDR *high, + enum bfd_endian byte_order, + unsigned int addr_size, + int signed_addr_p) +{ + CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); + + if (buf_end - loc_ptr < 2 * addr_size) + return DEBUG_LOC_BUFFER_OVERFLOW; + + if (signed_addr_p) + *low = extract_signed_integer (loc_ptr, addr_size, byte_order); + else + *low = extract_unsigned_integer (loc_ptr, addr_size, byte_order); + loc_ptr += addr_size; + + if (signed_addr_p) + *high = extract_signed_integer (loc_ptr, addr_size, byte_order); + else + *high = extract_unsigned_integer (loc_ptr, addr_size, byte_order); + loc_ptr += addr_size; + + *new_ptr = loc_ptr; + + /* A base-address-selection entry. */ + if ((*low & base_mask) == base_mask) + return DEBUG_LOC_BASE_ADDRESS; + + /* An end-of-list entry. */ + if (*low == 0 && *high == 0) + return DEBUG_LOC_END_OF_LIST; + + return DEBUG_LOC_START_END; +} + +/* Decode the addresses in .debug_loc.dwo entry. + A pointer to the next byte to examine is returned in *NEW_PTR. + The encoded low,high addresses are return in *LOW,*HIGH. + The result indicates the kind of entry found. */ + +static enum debug_loc_kind +decode_debug_loc_dwo_addresses (struct dwarf2_per_cu_data *per_cu, + const gdb_byte *loc_ptr, + const gdb_byte *buf_end, + const gdb_byte **new_ptr, + CORE_ADDR *low, CORE_ADDR *high, + enum bfd_endian byte_order) +{ + uint64_t low_index, high_index; + + if (loc_ptr == buf_end) + return DEBUG_LOC_BUFFER_OVERFLOW; + + switch (*loc_ptr++) + { + case DEBUG_LOC_END_OF_LIST: + *new_ptr = loc_ptr; + return DEBUG_LOC_END_OF_LIST; + case DEBUG_LOC_BASE_ADDRESS: + *low = 0; + loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &high_index); + if (loc_ptr == NULL) + return DEBUG_LOC_BUFFER_OVERFLOW; + *high = dwarf2_read_addr_index (per_cu, high_index); + *new_ptr = loc_ptr; + return DEBUG_LOC_BASE_ADDRESS; + case DEBUG_LOC_START_END: + loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &low_index); + if (loc_ptr == NULL) + return DEBUG_LOC_BUFFER_OVERFLOW; + *low = dwarf2_read_addr_index (per_cu, low_index); + loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &high_index); + if (loc_ptr == NULL) + return DEBUG_LOC_BUFFER_OVERFLOW; + *high = dwarf2_read_addr_index (per_cu, high_index); + *new_ptr = loc_ptr; + return DEBUG_LOC_START_END; + case DEBUG_LOC_START_LENGTH: + loc_ptr = gdb_read_uleb128 (loc_ptr, buf_end, &low_index); + if (loc_ptr == NULL) + return DEBUG_LOC_BUFFER_OVERFLOW; + *low = dwarf2_read_addr_index (per_cu, low_index); + if (loc_ptr + 4 > buf_end) + return DEBUG_LOC_BUFFER_OVERFLOW; + *high = *low; + *high += extract_unsigned_integer (loc_ptr, 4, byte_order); + *new_ptr = loc_ptr + 4; + return DEBUG_LOC_START_LENGTH; + default: + return DEBUG_LOC_INVALID_ENTRY; + } +} + /* A function for dealing with location lists. Given a symbol baton (BATON) and a pc value (PC), find the appropriate location expression, set *LOCEXPR_LENGTH, and return a pointer @@ -68,58 +203,64 @@ const gdb_byte * dwarf2_find_location_expression (struct dwarf2_loclist_baton *baton, size_t *locexpr_length, CORE_ADDR pc) { - CORE_ADDR low, high; - const gdb_byte *loc_ptr, *buf_end; - int length; struct objfile *objfile = dwarf2_per_cu_objfile (baton->per_cu); struct gdbarch *gdbarch = get_objfile_arch (objfile); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); unsigned int addr_size = dwarf2_per_cu_addr_size (baton->per_cu); int signed_addr_p = bfd_get_sign_extend_vma (objfile->obfd); - CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); /* Adjust base_address for relocatable objects. */ CORE_ADDR base_offset = dwarf2_per_cu_text_offset (baton->per_cu); CORE_ADDR base_address = baton->base_address + base_offset; + const gdb_byte *loc_ptr, *buf_end; loc_ptr = baton->data; buf_end = baton->data + baton->size; while (1) { - if (buf_end - loc_ptr < 2 * addr_size) - error (_("dwarf2_find_location_expression: " - "Corrupted DWARF expression.")); - - if (signed_addr_p) - low = extract_signed_integer (loc_ptr, addr_size, byte_order); - else - low = extract_unsigned_integer (loc_ptr, addr_size, byte_order); - loc_ptr += addr_size; - - if (signed_addr_p) - high = extract_signed_integer (loc_ptr, addr_size, byte_order); + CORE_ADDR low = 0, high = 0; /* init for gcc -Wall */ + int length; + enum debug_loc_kind kind; + const gdb_byte *new_ptr = NULL; /* init for gcc -Wall */ + + if (baton->from_dwo) + kind = decode_debug_loc_dwo_addresses (baton->per_cu, + loc_ptr, buf_end, &new_ptr, + &low, &high, byte_order); else - high = extract_unsigned_integer (loc_ptr, addr_size, byte_order); - loc_ptr += addr_size; - - /* A base-address-selection entry. */ - if ((low & base_mask) == base_mask) + kind = decode_debug_loc_addresses (loc_ptr, buf_end, &new_ptr, + &low, &high, + byte_order, addr_size, + signed_addr_p); + loc_ptr = new_ptr; + switch (kind) { + case DEBUG_LOC_END_OF_LIST: + *locexpr_length = 0; + return NULL; + case DEBUG_LOC_BASE_ADDRESS: base_address = high + base_offset; continue; + case DEBUG_LOC_START_END: + case DEBUG_LOC_START_LENGTH: + break; + case DEBUG_LOC_BUFFER_OVERFLOW: + case DEBUG_LOC_INVALID_ENTRY: + error (_("dwarf2_find_location_expression: " + "Corrupted DWARF expression.")); + default: + gdb_assert_not_reached ("bad debug_loc_kind"); } - /* An end-of-list entry. */ - if (low == 0 && high == 0) + /* Otherwise, a location expression entry. + If the entry is from a DWO, don't add base address: the entry is + from .debug_addr which has absolute addresses. */ + if (! baton->from_dwo) { - *locexpr_length = 0; - return NULL; + low += base_address; + high += base_address; } - /* Otherwise, a location expression entry. */ - low += base_address; - high += base_address; - length = extract_unsigned_integer (loc_ptr, 2, byte_order); loc_ptr += 2; @@ -196,11 +337,15 @@ dwarf_expr_frame_base (void *baton, const gdb_byte **start, size_t * length) this_base method. */ struct symbol *framefunc; struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; + struct block *bl = get_frame_block (debaton->frame, NULL); + + if (bl == NULL) + error (_("frame address is not available.")); /* 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)); + framefunc = block_linkage_function (bl); /* 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, @@ -282,15 +427,14 @@ dwarf_expr_tls_address (void *baton, CORE_ADDR offset) call and return. */ static void -per_cu_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset, +per_cu_dwarf_call (struct dwarf_expr_context *ctx, cu_offset die_offset, struct dwarf2_per_cu_data *per_cu, CORE_ADDR (*get_frame_pc) (void *baton), void *baton) { struct dwarf2_locexpr_baton block; - block = dwarf2_fetch_die_location_block (die_offset, per_cu, - get_frame_pc, baton); + block = dwarf2_fetch_die_loc_cu_off (die_offset, per_cu, get_frame_pc, baton); /* DW_OP_call_ref is currently not supported. */ gdb_assert (block.per_cu == per_cu); @@ -301,7 +445,7 @@ per_cu_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset, /* Helper interface of per_cu_dwarf_call for dwarf2_evaluate_loc_desc. */ static void -dwarf_expr_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset) +dwarf_expr_dwarf_call (struct dwarf_expr_context *ctx, cu_offset die_offset) { struct dwarf_expr_baton *debaton = ctx->baton; @@ -312,7 +456,8 @@ dwarf_expr_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset) /* Callback function for dwarf2_evaluate_loc_desc. */ static struct type * -dwarf_expr_get_base_type (struct dwarf_expr_context *ctx, size_t die_offset) +dwarf_expr_get_base_type (struct dwarf_expr_context *ctx, + cu_offset die_offset) { struct dwarf_expr_baton *debaton = ctx->baton; @@ -321,7 +466,7 @@ dwarf_expr_get_base_type (struct dwarf_expr_context *ctx, size_t die_offset) /* See dwarf2loc.h. */ -int entry_values_debug = 0; +unsigned int entry_values_debug = 0; /* Helper to set entry_values_debug. */ @@ -397,7 +542,9 @@ call_site_to_target_addr (struct gdbarch *call_site_gdbarch, struct minimal_symbol *msym; physname = FIELD_STATIC_PHYSNAME (call_site->target); - msym = lookup_minimal_symbol_text (physname, NULL); + + /* Handle both the mangled and demangled PHYSNAME. */ + msym = lookup_minimal_symbol (physname, NULL, NULL); if (msym == NULL) { msym = lookup_minimal_symbol_by_pc (call_site->pc - 1); @@ -648,7 +795,7 @@ static struct call_site_chain * call_site_find_chain_1 (struct gdbarch *gdbarch, CORE_ADDR caller_pc, CORE_ADDR callee_pc) { - struct func_type *func_specific; + CORE_ADDR save_callee_pc = callee_pc; struct obstack addr_obstack; struct cleanup *back_to_retval, *back_to_workdata; struct call_site_chain *retval = NULL; @@ -667,7 +814,7 @@ call_site_find_chain_1 (struct gdbarch *gdbarch, CORE_ADDR caller_pc, callee_pc = get_pc_function_start (callee_pc); if (callee_pc == 0) throw_error (NO_ENTRY_VALUE_ERROR, _("Unable to find function for PC %s"), - paddress (gdbarch, callee_pc)); + paddress (gdbarch, save_callee_pc)); back_to_retval = make_cleanup (free_current_contents, &retval); @@ -812,30 +959,56 @@ call_site_find_chain (struct gdbarch *gdbarch, CORE_ADDR caller_pc, return retval; } -/* Fetch call_site_parameter from caller matching the parameters. FRAME is for - callee. See DWARF_REG and FB_OFFSET description at struct - dwarf_expr_context_funcs->push_dwarf_reg_entry_value. +/* Return 1 if KIND and KIND_U match PARAMETER. Return 0 otherwise. */ + +static int +call_site_parameter_matches (struct call_site_parameter *parameter, + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u) +{ + if (kind == parameter->kind) + switch (kind) + { + case CALL_SITE_PARAMETER_DWARF_REG: + return kind_u.dwarf_reg == parameter->u.dwarf_reg; + case CALL_SITE_PARAMETER_FB_OFFSET: + return kind_u.fb_offset == parameter->u.fb_offset; + case CALL_SITE_PARAMETER_PARAM_OFFSET: + return kind_u.param_offset.cu_off == parameter->u.param_offset.cu_off; + } + return 0; +} + +/* Fetch call_site_parameter from caller matching KIND and KIND_U. + FRAME is for callee. Function always returns non-NULL, it throws NO_ENTRY_VALUE_ERROR otherwise. */ static struct call_site_parameter * -dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, int dwarf_reg, - CORE_ADDR fb_offset, +dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u, struct dwarf2_per_cu_data **per_cu_return) { - CORE_ADDR func_addr = get_frame_func (frame); - CORE_ADDR caller_pc; - struct gdbarch *gdbarch = get_frame_arch (frame); - struct frame_info *caller_frame = get_prev_frame (frame); + CORE_ADDR func_addr, caller_pc; + struct gdbarch *gdbarch; + struct frame_info *caller_frame; struct call_site *call_site; int iparams; - struct value *val; - struct dwarf2_locexpr_baton *dwarf_block; /* Initialize it just to avoid a GCC false warning. */ struct call_site_parameter *parameter = NULL; CORE_ADDR target_addr; + while (get_frame_type (frame) == INLINE_FRAME) + { + frame = get_prev_frame (frame); + gdb_assert (frame != NULL); + } + + func_addr = get_frame_func (frame); + gdbarch = get_frame_arch (frame); + caller_frame = get_prev_frame (frame); if (gdbarch != frame_unwind_arch (frame)) { struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (func_addr); @@ -886,12 +1059,7 @@ dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, int dwarf_reg, for (iparams = 0; iparams < call_site->parameter_count; iparams++) { parameter = &call_site->parameter[iparams]; - if (parameter->dwarf_reg == -1 && dwarf_reg == -1) - { - if (parameter->fb_offset == fb_offset) - break; - } - else if (parameter->dwarf_reg == dwarf_reg) + if (call_site_parameter_matches (parameter, kind, kind_u)) break; } if (iparams == call_site->parameter_count) @@ -948,17 +1116,17 @@ dwarf_entry_parameter_to_value (struct call_site_parameter *parameter, return dwarf2_evaluate_loc_desc (type, caller_frame, data, size + 1, per_cu); } -/* Execute call_site_parameter's DWARF block matching DEREF_SIZE for caller of - the CTX's frame. CTX must be of dwarf_expr_ctx_funcs kind. See DWARF_REG - and FB_OFFSET description at struct - dwarf_expr_context_funcs->push_dwarf_reg_entry_value. +/* Execute DWARF block of call_site_parameter which matches KIND and KIND_U. + Choose DEREF_SIZE value of that parameter. Search caller of the CTX's + frame. CTX must be of dwarf_expr_ctx_funcs kind. The CTX caller can be from a different CU - per_cu_dwarf_call implementation can be more simple as it does not support cross-CU DWARF executions. */ static void dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, - int dwarf_reg, CORE_ADDR fb_offset, + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u, int deref_size) { struct dwarf_expr_baton *debaton; @@ -975,7 +1143,7 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, frame = debaton->frame; caller_frame = get_prev_frame (frame); - parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset, + parameter = dwarf_expr_reg_to_entry_parameter (frame, kind, kind_u, &caller_per_cu); data_src = deref_size == -1 ? parameter->value : parameter->data_value; size = deref_size == -1 ? parameter->value_size : parameter->data_value_size; @@ -1005,6 +1173,17 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, ctx->baton = saved_ctx.baton; } +/* Callback function for dwarf2_evaluate_loc_desc. + Fetch the address indexed by DW_OP_GNU_addr_index. */ + +static CORE_ADDR +dwarf_expr_get_addr_index (void *baton, unsigned int index) +{ + struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; + + return dwarf2_read_addr_index (debaton->per_cu, index); +} + /* VALUE must be of type lval_computed with entry_data_value_funcs. Perform the indirect method on it, that is use its stored target value, the sole purpose of entry_data_value_funcs.. */ @@ -1061,17 +1240,17 @@ static const struct lval_funcs entry_data_value_funcs = entry_data_value_free_closure }; -/* Read parameter of TYPE at (callee) FRAME's function entry. DWARF_REG and - FB_OFFSET are used to match DW_AT_location at the caller's - DW_TAG_GNU_call_site_parameter. See DWARF_REG and FB_OFFSET description at - struct dwarf_expr_context_funcs->push_dwarf_reg_entry_value. +/* Read parameter of TYPE at (callee) FRAME's function entry. KIND and KIND_U + are used to match DW_AT_location at the caller's + DW_TAG_GNU_call_site_parameter. Function always returns non-NULL value. It throws NO_ENTRY_VALUE_ERROR if it cannot resolve the parameter for any reason. */ static struct value * value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame, - int dwarf_reg, CORE_ADDR fb_offset) + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u) { struct type *checked_type = check_typedef (type); struct type *target_type = TYPE_TARGET_TYPE (checked_type); @@ -1081,7 +1260,7 @@ value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame, struct dwarf2_per_cu_data *caller_per_cu; CORE_ADDR addr; - parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset, + parameter = dwarf_expr_reg_to_entry_parameter (frame, kind, kind_u, &caller_per_cu); outer_val = dwarf_entry_parameter_to_value (parameter, -1 /* deref_size */, @@ -1133,15 +1312,16 @@ static struct value * value_of_dwarf_block_entry (struct type *type, struct frame_info *frame, const gdb_byte *block, size_t block_len) { - int dwarf_reg; - CORE_ADDR fb_offset; + union call_site_parameter_u kind_u; - dwarf_reg = dwarf_block_to_dwarf_reg (block, block + block_len); - if (dwarf_reg != -1) - return value_of_dwarf_reg_entry (type, frame, dwarf_reg, 0 /* unused */); + kind_u.dwarf_reg = dwarf_block_to_dwarf_reg (block, block + block_len); + if (kind_u.dwarf_reg != -1) + return value_of_dwarf_reg_entry (type, frame, CALL_SITE_PARAMETER_DWARF_REG, + kind_u); - if (dwarf_block_to_fb_offset (block, block + block_len, &fb_offset)) - return value_of_dwarf_reg_entry (type, frame, -1, fb_offset); + if (dwarf_block_to_fb_offset (block, block + block_len, &kind_u.fb_offset)) + return value_of_dwarf_reg_entry (type, frame, CALL_SITE_PARAMETER_FB_OFFSET, + kind_u); /* This can normally happen - throw NO_ENTRY_VALUE_ERROR to get the message suppressed during normal operation. The expression can be arbitrary if @@ -1865,9 +2045,10 @@ indirect_pieced_value (struct value *value) byte_offset = value_as_address (value); gdb_assert (piece); - baton = dwarf2_fetch_die_location_block (piece->v.ptr.die, c->per_cu, - get_frame_address_in_block_wrapper, - frame); + baton + = dwarf2_fetch_die_loc_sect_off (piece->v.ptr.die, c->per_cu, + get_frame_address_in_block_wrapper, + frame); return dwarf2_evaluate_loc_desc_full (TYPE_TARGET_TYPE (type), frame, baton.data, baton.size, baton.per_cu, @@ -1939,7 +2120,8 @@ static const struct dwarf_expr_context_funcs dwarf_expr_ctx_funcs = dwarf_expr_tls_address, dwarf_expr_dwarf_call, dwarf_expr_get_base_type, - dwarf_expr_push_dwarf_reg_entry_value + dwarf_expr_push_dwarf_reg_entry_value, + dwarf_expr_get_addr_index }; /* Evaluate a location description, starting at DATA and with length @@ -1949,7 +2131,7 @@ static const struct dwarf_expr_context_funcs dwarf_expr_ctx_funcs = static struct value * dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, - const gdb_byte *data, unsigned short size, + const gdb_byte *data, size_t size, struct dwarf2_per_cu_data *per_cu, LONGEST byte_offset) { @@ -2150,7 +2332,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, struct value * dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame, - const gdb_byte *data, unsigned short size, + const gdb_byte *data, size_t size, struct dwarf2_per_cu_data *per_cu) { return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu, 0); @@ -2219,7 +2401,7 @@ needs_frame_tls_address (void *baton, CORE_ADDR offset) /* Helper interface of per_cu_dwarf_call for dwarf2_loc_desc_needs_frame. */ static void -needs_frame_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset) +needs_frame_dwarf_call (struct dwarf_expr_context *ctx, cu_offset die_offset) { struct needs_frame_baton *nf_baton = ctx->baton; @@ -2231,11 +2413,24 @@ needs_frame_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset) static void needs_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, - int dwarf_reg, CORE_ADDR fb_offset, int deref_size) + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u, int deref_size) { struct needs_frame_baton *nf_baton = ctx->baton; nf_baton->needs_frame = 1; + + /* The expression may require some stub values on DWARF stack. */ + dwarf_expr_push_address (ctx, 0, 0); +} + +/* DW_OP_GNU_addr_index doesn't require a frame. */ + +static CORE_ADDR +needs_get_addr_index (void *baton, unsigned int index) +{ + /* Nothing to do. */ + return 1; } /* Virtual method table for dwarf2_loc_desc_needs_frame below. */ @@ -2250,14 +2445,15 @@ static const struct dwarf_expr_context_funcs needs_frame_ctx_funcs = needs_frame_tls_address, needs_frame_dwarf_call, NULL, /* get_base_type */ - needs_dwarf_reg_entry_value + needs_dwarf_reg_entry_value, + needs_get_addr_index }; /* Return non-zero iff the location expression at DATA (length SIZE) requires a frame to evaluate. */ static int -dwarf2_loc_desc_needs_frame (const gdb_byte *data, unsigned short size, +dwarf2_loc_desc_needs_frame (const gdb_byte *data, size_t size, struct dwarf2_per_cu_data *per_cu) { struct needs_frame_baton baton; @@ -2306,7 +2502,7 @@ dwarf2_loc_desc_needs_frame (const gdb_byte *data, unsigned short size, static void unimplemented (unsigned int op) { - const char *name = dwarf_stack_op_name (op); + const char *name = get_DW_OP_name (op); if (name) error (_("DWARF operator %s cannot be translated to an agent expression"), @@ -2343,7 +2539,7 @@ access_memory (struct gdbarch *arch, struct agent_expr *expr, ULONGEST nbits) { ULONGEST nbytes = (nbits + 7) / 8; - gdb_assert (nbits > 0 && nbits <= sizeof (LONGEST)); + gdb_assert (nbytes > 0 && nbytes <= sizeof (LONGEST)); if (trace_kludge) ax_trace_quick (expr, nbytes); @@ -2429,8 +2625,8 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, while (op_ptr < op_end) { enum dwarf_location_atom op = *op_ptr; - ULONGEST uoffset, reg; - LONGEST offset; + uint64_t uoffset, reg; + int64_t offset; int i; offsets[op_ptr - base] = expr->len; @@ -2534,11 +2730,11 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, op_ptr += 8; break; case DW_OP_constu: - op_ptr = read_uleb128 (op_ptr, op_end, &uoffset); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset); ax_const_l (expr, uoffset); break; case DW_OP_consts: - op_ptr = read_sleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset); ax_const_l (expr, offset); break; @@ -2580,7 +2776,7 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, break; case DW_OP_regx: - op_ptr = read_uleb128 (op_ptr, op_end, ®); + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®); dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx"); loc->u.reg = translate_register (arch, reg); loc->kind = axs_lvalue_register; @@ -2588,9 +2784,9 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, case DW_OP_implicit_value: { - ULONGEST len; + uint64_t len; - op_ptr = read_uleb128 (op_ptr, op_end, &len); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &len); if (op_ptr + len > op_end) error (_("DW_OP_implicit_value: too few bytes available.")); if (len > sizeof (ULONGEST)) @@ -2644,7 +2840,7 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: - op_ptr = read_sleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset); i = translate_register (arch, op - DW_OP_breg0); ax_reg (expr, i); if (offset != 0) @@ -2655,8 +2851,8 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, break; case DW_OP_bregx: { - op_ptr = read_uleb128 (op_ptr, op_end, ®); - op_ptr = read_sleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset); i = translate_register (arch, reg); ax_reg (expr, i); if (offset != 0) @@ -2670,10 +2866,8 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, { const gdb_byte *datastart; size_t datalen; - unsigned int before_stack_len; struct block *b; struct symbol *framefunc; - LONGEST base_offset = 0; b = block_for_pc (expr->scope); @@ -2688,9 +2882,11 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, dwarf_expr_frame_base_1 (framefunc, expr->scope, &datastart, &datalen); - op_ptr = read_sleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset); dwarf2_compile_expr_to_ax (expr, loc, arch, addr_size, datastart, datastart + datalen, per_cu); + if (loc->kind == axs_lvalue_register) + require_rvalue (expr, loc); if (offset != 0) { @@ -2737,26 +2933,10 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, else size = addr_size; - switch (size) - { - case 8: - ax_simple (expr, aop_ref8); - break; - case 16: - ax_simple (expr, aop_ref16); - break; - case 32: - ax_simple (expr, aop_ref32); - break; - case 64: - ax_simple (expr, aop_ref64); - break; - default: - /* Note that dwarf_stack_op_name will never return - NULL here. */ - error (_("Unsupported size %d in %s"), - size, dwarf_stack_op_name (op)); - } + if (size != 1 && size != 2 && size != 4 && size != 8) + error (_("Unsupported size %d in %s"), + size, get_DW_OP_name (op)); + access_memory (arch, expr, size * TARGET_CHAR_BIT); } break; @@ -2789,7 +2969,7 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, break; case DW_OP_plus_uconst: - op_ptr = read_uleb128 (op_ptr, op_end, ®); + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®); /* It would be really weird to emit `DW_OP_plus_uconst 0', but we micro-optimize anyhow. */ if (reg != 0) @@ -2939,20 +3119,20 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, case DW_OP_piece: case DW_OP_bit_piece: { - ULONGEST size, offset; + uint64_t size, offset; if (op_ptr - 1 == previous_piece) error (_("Cannot translate empty pieces to agent expressions")); previous_piece = op_ptr - 1; - op_ptr = read_uleb128 (op_ptr, op_end, &size); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &size); if (op == DW_OP_piece) { size *= 8; offset = 0; } else - op_ptr = read_uleb128 (op_ptr, op_end, &offset); + op_ptr = safe_read_uleb128 (op_ptr, op_end, &offset); if (bits_collected + size > 8 * sizeof (LONGEST)) error (_("Expression pieces exceed word size")); @@ -3012,12 +3192,14 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc, { struct dwarf2_locexpr_baton block; int size = (op == DW_OP_call2 ? 2 : 4); + cu_offset offset; uoffset = extract_unsigned_integer (op_ptr, size, byte_order); op_ptr += size; - block = dwarf2_fetch_die_location_block (uoffset, per_cu, - get_ax_pc, expr); + offset.cu_off = uoffset; + block = dwarf2_fetch_die_loc_cu_off (offset, per_cu, + get_ax_pc, expr); /* DW_OP_call_ref is currently not supported. */ gdb_assert (block.per_cu == per_cu); @@ -3110,15 +3292,18 @@ locexpr_regname (struct gdbarch *gdbarch, int dwarf_regnum) /* Nicely describe a single piece of a location, returning an updated position in the bytecode sequence. This function cannot recognize all locations; if a location is not recognized, it simply returns - DATA. */ + DATA. If there is an error during reading, e.g. we run off the end + of the buffer, an error is thrown. */ static const gdb_byte * locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, CORE_ADDR addr, struct objfile *objfile, + struct dwarf2_per_cu_data *per_cu, const gdb_byte *data, const gdb_byte *end, unsigned int addr_size) { struct gdbarch *gdbarch = get_objfile_arch (objfile); + size_t leb128_size; if (data[0] >= DW_OP_reg0 && data[0] <= DW_OP_reg31) { @@ -3128,9 +3313,9 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, } else if (data[0] == DW_OP_regx) { - ULONGEST reg; + uint64_t reg; - data = read_uleb128 (data + 1, end, ®); + data = safe_read_uleb128 (data + 1, end, ®); fprintf_filtered (stream, _("a variable in $%s"), locexpr_regname (gdbarch, reg)); } @@ -3139,12 +3324,12 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, struct block *b; struct symbol *framefunc; int frame_reg = 0; - LONGEST frame_offset; + int64_t frame_offset; const gdb_byte *base_data, *new_data, *save_data = data; size_t base_size; - LONGEST base_offset = 0; + int64_t base_offset = 0; - new_data = read_sleb128 (data + 1, end, &frame_offset); + new_data = safe_read_sleb128 (data + 1, end, &frame_offset); if (!piece_end_p (new_data, end)) return data; data = new_data; @@ -3168,8 +3353,8 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, const gdb_byte *buf_end; frame_reg = base_data[0] - DW_OP_breg0; - buf_end = read_sleb128 (base_data + 1, - base_data + base_size, &base_offset); + buf_end = safe_read_sleb128 (base_data + 1, base_data + base_size, + &base_offset); if (buf_end != base_data + base_size) error (_("Unexpected opcode after " "DW_OP_breg%u for symbol \"%s\"."), @@ -3196,9 +3381,9 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31 && piece_end_p (data, end)) { - LONGEST offset; + int64_t offset; - data = read_sleb128 (data + 1, end, &offset); + data = safe_read_sleb128 (data + 1, end, &offset); fprintf_filtered (stream, _("a variable at offset %s from base reg $%s"), @@ -3238,6 +3423,29 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, data += 1 + addr_size + 1; } + + /* With -gsplit-dwarf a TLS variable can also look like this: + DW_AT_location : 3 byte block: fc 4 e0 + (DW_OP_GNU_const_index: 4; + DW_OP_GNU_push_tls_address) */ + else if (data + 3 <= end + && data + 1 + (leb128_size = skip_leb128 (data + 1, end)) < end + && data[0] == DW_OP_GNU_const_index + && leb128_size > 0 + && data[1 + leb128_size] == DW_OP_GNU_push_tls_address + && piece_end_p (data + 2 + leb128_size, end)) + { + uint64_t offset; + + data = safe_read_uleb128 (data + 1, end, &offset); + offset = dwarf2_read_addr_index (per_cu, offset); + fprintf_filtered (stream, + _("a thread-local variable at offset 0x%s " + "in the thread-local storage for `%s'"), + phex_nz (offset, addr_size), objfile->name); + ++data; + } + else if (data[0] >= DW_OP_lit0 && data[0] <= DW_OP_lit31 && data + 1 < end @@ -3253,7 +3461,9 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, /* Disassemble an expression, stopping at the end of a piece or at the end of the expression. Returns a pointer to the next unread byte in the input expression. If ALL is nonzero, then this function - will keep going until it reaches the end of the expression. */ + will keep going until it reaches the end of the expression. + If there is an error during reading, e.g. we run off the end + of the buffer, an error is thrown. */ static const gdb_byte * disassemble_dwarf_expression (struct ui_file *stream, @@ -3268,11 +3478,11 @@ disassemble_dwarf_expression (struct ui_file *stream, || (data[0] != DW_OP_piece && data[0] != DW_OP_bit_piece))) { enum dwarf_location_atom op = *data++; - ULONGEST ul; - LONGEST l; + uint64_t ul; + int64_t l; const char *name; - name = dwarf_stack_op_name (op); + name = get_DW_OP_name (op); if (!name) error (_("Unrecognized DWARF opcode 0x%02x at %ld"), @@ -3330,11 +3540,11 @@ disassemble_dwarf_expression (struct ui_file *stream, fprintf_filtered (stream, " %s", plongest (l)); break; case DW_OP_constu: - data = read_uleb128 (data, end, &ul); + data = safe_read_uleb128 (data, end, &ul); fprintf_filtered (stream, " %s", pulongest (ul)); break; case DW_OP_consts: - data = read_sleb128 (data, end, &l); + data = safe_read_sleb128 (data, end, &l); fprintf_filtered (stream, " %s", plongest (l)); break; @@ -3375,13 +3585,13 @@ disassemble_dwarf_expression (struct ui_file *stream, break; case DW_OP_regx: - data = read_uleb128 (data, end, &ul); + data = safe_read_uleb128 (data, end, &ul); fprintf_filtered (stream, " %s [$%s]", pulongest (ul), locexpr_regname (arch, (int) ul)); break; case DW_OP_implicit_value: - data = read_uleb128 (data, end, &ul); + data = safe_read_uleb128 (data, end, &ul); data += ul; fprintf_filtered (stream, " %s", pulongest (ul)); break; @@ -3418,14 +3628,14 @@ disassemble_dwarf_expression (struct ui_file *stream, case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: - data = read_sleb128 (data, end, &l); + data = safe_read_sleb128 (data, end, &l); fprintf_filtered (stream, " %s [$%s]", plongest (l), locexpr_regname (arch, op - DW_OP_breg0)); break; case DW_OP_bregx: - data = read_uleb128 (data, end, &ul); - data = read_sleb128 (data, end, &l); + data = safe_read_uleb128 (data, end, &ul); + data = safe_read_sleb128 (data, end, &l); fprintf_filtered (stream, " register %s [$%s] offset %s", pulongest (ul), locexpr_regname (arch, (int) ul), @@ -3433,7 +3643,7 @@ disassemble_dwarf_expression (struct ui_file *stream, break; case DW_OP_fbreg: - data = read_sleb128 (data, end, &l); + data = safe_read_sleb128 (data, end, &l); fprintf_filtered (stream, " %s", plongest (l)); break; @@ -3445,7 +3655,7 @@ disassemble_dwarf_expression (struct ui_file *stream, break; case DW_OP_plus_uconst: - data = read_uleb128 (data, end, &ul); + data = safe_read_uleb128 (data, end, &ul); fprintf_filtered (stream, " %s", pulongest (ul)); break; @@ -3483,16 +3693,16 @@ disassemble_dwarf_expression (struct ui_file *stream, break; case DW_OP_piece: - data = read_uleb128 (data, end, &ul); + data = safe_read_uleb128 (data, end, &ul); fprintf_filtered (stream, " %s (bytes)", pulongest (ul)); break; case DW_OP_bit_piece: { - ULONGEST offset; + uint64_t offset; - data = read_uleb128 (data, end, &ul); - data = read_uleb128 (data, end, &offset); + data = safe_read_uleb128 (data, end, &ul); + data = safe_read_uleb128 (data, end, &offset); fprintf_filtered (stream, " size %s offset %s (bits)", pulongest (ul), pulongest (offset)); } @@ -3504,7 +3714,7 @@ disassemble_dwarf_expression (struct ui_file *stream, gdbarch_byte_order (arch)); data += offset_size; - data = read_sleb128 (data, end, &l); + data = safe_read_sleb128 (data, end, &l); fprintf_filtered (stream, " DIE %s offset %s", phex_nz (ul, offset_size), @@ -3515,43 +3725,48 @@ disassemble_dwarf_expression (struct ui_file *stream, case DW_OP_GNU_deref_type: { int addr_size = *data++; - ULONGEST offset; + cu_offset offset; struct type *type; - data = read_uleb128 (data, end, &offset); + data = safe_read_uleb128 (data, end, &ul); + offset.cu_off = ul; type = dwarf2_get_die_type (offset, per_cu); fprintf_filtered (stream, "<"); type_print (type, "", stream, -1); - fprintf_filtered (stream, " [0x%s]> %d", phex_nz (offset, 0), + fprintf_filtered (stream, " [0x%s]> %d", phex_nz (offset.cu_off, 0), addr_size); } break; case DW_OP_GNU_const_type: { - ULONGEST type_die; + cu_offset type_die; struct type *type; - data = read_uleb128 (data, end, &type_die); + data = safe_read_uleb128 (data, end, &ul); + type_die.cu_off = ul; type = dwarf2_get_die_type (type_die, per_cu); fprintf_filtered (stream, "<"); type_print (type, "", stream, -1); - fprintf_filtered (stream, " [0x%s]>", phex_nz (type_die, 0)); + fprintf_filtered (stream, " [0x%s]>", phex_nz (type_die.cu_off, 0)); } break; case DW_OP_GNU_regval_type: { - ULONGEST type_die, reg; + uint64_t reg; + cu_offset type_die; struct type *type; - data = read_uleb128 (data, end, ®); - data = read_uleb128 (data, end, &type_die); + data = safe_read_uleb128 (data, end, ®); + data = safe_read_uleb128 (data, end, &ul); + type_die.cu_off = ul; type = dwarf2_get_die_type (type_die, per_cu); fprintf_filtered (stream, "<"); type_print (type, "", stream, -1); - fprintf_filtered (stream, " [0x%s]> [$%s]", phex_nz (type_die, 0), + fprintf_filtered (stream, " [0x%s]> [$%s]", + phex_nz (type_die.cu_off, 0), locexpr_regname (arch, reg)); } break; @@ -3559,11 +3774,12 @@ disassemble_dwarf_expression (struct ui_file *stream, case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: { - ULONGEST type_die; + cu_offset type_die; - data = read_uleb128 (data, end, &type_die); + data = safe_read_uleb128 (data, end, &ul); + type_die.cu_off = ul; - if (type_die == 0) + if (type_die.cu_off == 0) fprintf_filtered (stream, "<0>"); else { @@ -3572,19 +3788,36 @@ disassemble_dwarf_expression (struct ui_file *stream, type = dwarf2_get_die_type (type_die, per_cu); fprintf_filtered (stream, "<"); type_print (type, "", stream, -1); - fprintf_filtered (stream, " [0x%s]>", phex_nz (type_die, 0)); + fprintf_filtered (stream, " [0x%s]>", phex_nz (type_die.cu_off, 0)); } } break; case DW_OP_GNU_entry_value: - data = read_uleb128 (data, end, &ul); + data = safe_read_uleb128 (data, end, &ul); fputc_filtered ('\n', stream); disassemble_dwarf_expression (stream, arch, addr_size, offset_size, start, data, data + ul, indent + 2, all, per_cu); data += ul; continue; + + case DW_OP_GNU_parameter_ref: + ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch)); + data += 4; + fprintf_filtered (stream, " offset %s", phex_nz (ul, 4)); + break; + + case DW_OP_GNU_addr_index: + data = safe_read_uleb128 (data, end, &ul); + ul = dwarf2_read_addr_index (per_cu, ul); + fprintf_filtered (stream, " 0x%s", phex_nz (ul, addr_size)); + break; + case DW_OP_GNU_const_index: + data = safe_read_uleb128 (data, end, &ul); + ul = dwarf2_read_addr_index (per_cu, ul); + fprintf_filtered (stream, " %s", pulongest (ul)); + break; } fprintf_filtered (stream, "\n"); @@ -3599,7 +3832,7 @@ disassemble_dwarf_expression (struct ui_file *stream, static void locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr, struct ui_file *stream, - const gdb_byte *data, int size, + const gdb_byte *data, size_t size, struct objfile *objfile, unsigned int addr_size, int offset_size, struct dwarf2_per_cu_data *per_cu) { @@ -3619,7 +3852,7 @@ locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr, if (!dwarf2_always_disassemble) { data = locexpr_describe_location_piece (symbol, stream, - addr, objfile, + addr, objfile, per_cu, data, end, addr_size); /* If we printed anything, or if we have an empty piece, then don't disassemble. */ @@ -3647,9 +3880,9 @@ locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr, fprintf_filtered (stream, " "); if (data[0] == DW_OP_piece) { - ULONGEST bytes; + uint64_t bytes; - data = read_uleb128 (data + 1, end, &bytes); + data = safe_read_uleb128 (data + 1, end, &bytes); if (empty) fprintf_filtered (stream, _("an empty %s-byte piece"), @@ -3660,10 +3893,10 @@ locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr, } else if (data[0] == DW_OP_bit_piece) { - ULONGEST bits, offset; + uint64_t bits, offset; - data = read_uleb128 (data + 1, end, &bits); - data = read_uleb128 (data, end, &offset); + data = safe_read_uleb128 (data + 1, end, &bits); + data = safe_read_uleb128 (data, end, &offset); if (empty) fprintf_filtered (stream, @@ -3803,19 +4036,17 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr, struct ui_file *stream) { struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); - CORE_ADDR low, high; const gdb_byte *loc_ptr, *buf_end; - int length, first = 1; struct objfile *objfile = dwarf2_per_cu_objfile (dlbaton->per_cu); struct gdbarch *gdbarch = get_objfile_arch (objfile); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu); int offset_size = dwarf2_per_cu_offset_size (dlbaton->per_cu); int signed_addr_p = bfd_get_sign_extend_vma (objfile->obfd); - CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); /* Adjust base_address for relocatable objects. */ CORE_ADDR base_offset = dwarf2_per_cu_text_offset (dlbaton->per_cu); CORE_ADDR base_address = dlbaton->base_address + base_offset; + int done = 0; loc_ptr = dlbaton->data; buf_end = dlbaton->data + dlbaton->size; @@ -3823,37 +4054,44 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr, fprintf_filtered (stream, _("multi-location:\n")); /* Iterate through locations until we run out. */ - while (1) + while (!done) { - if (buf_end - loc_ptr < 2 * addr_size) - error (_("Corrupted DWARF expression for symbol \"%s\"."), - SYMBOL_PRINT_NAME (symbol)); - - if (signed_addr_p) - low = extract_signed_integer (loc_ptr, addr_size, byte_order); - else - low = extract_unsigned_integer (loc_ptr, addr_size, byte_order); - loc_ptr += addr_size; - - if (signed_addr_p) - high = extract_signed_integer (loc_ptr, addr_size, byte_order); + CORE_ADDR low = 0, high = 0; /* init for gcc -Wall */ + int length; + enum debug_loc_kind kind; + const gdb_byte *new_ptr = NULL; /* init for gcc -Wall */ + + if (dlbaton->from_dwo) + kind = decode_debug_loc_dwo_addresses (dlbaton->per_cu, + loc_ptr, buf_end, &new_ptr, + &low, &high, byte_order); else - high = extract_unsigned_integer (loc_ptr, addr_size, byte_order); - loc_ptr += addr_size; - - /* A base-address-selection entry. */ - if ((low & base_mask) == base_mask) + kind = decode_debug_loc_addresses (loc_ptr, buf_end, &new_ptr, + &low, &high, + byte_order, addr_size, + signed_addr_p); + loc_ptr = new_ptr; + switch (kind) { + case DEBUG_LOC_END_OF_LIST: + done = 1; + continue; + case DEBUG_LOC_BASE_ADDRESS: base_address = high + base_offset; fprintf_filtered (stream, _(" Base address %s"), paddress (gdbarch, base_address)); continue; + case DEBUG_LOC_START_END: + case DEBUG_LOC_START_LENGTH: + break; + case DEBUG_LOC_BUFFER_OVERFLOW: + case DEBUG_LOC_INVALID_ENTRY: + error (_("Corrupted DWARF expression for symbol \"%s\"."), + SYMBOL_PRINT_NAME (symbol)); + default: + gdb_assert_not_reached ("bad debug_loc_kind"); } - /* An end-of-list entry. */ - if (low == 0 && high == 0) - break; - /* Otherwise, a location expression entry. */ low += base_address; high += base_address; @@ -3906,19 +4144,22 @@ const struct symbol_computed_ops dwarf2_loclist_funcs = { loclist_tracepoint_var_ref }; +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_dwarf2loc; + void _initialize_dwarf2loc (void) { - add_setshow_zinteger_cmd ("entry-values", class_maintenance, - &entry_values_debug, - _("Set entry values and tail call frames " - "debugging."), - _("Show entry values and tail call frames " - "debugging."), - _("When non-zero, the process of determining " - "parameter values from function entry point " - "and tail call frames will be printed."), - NULL, - show_entry_values_debug, - &setdebuglist, &showdebuglist); + add_setshow_zuinteger_cmd ("entry-values", class_maintenance, + &entry_values_debug, + _("Set entry values and tail call frames " + "debugging."), + _("Show entry values and tail call frames " + "debugging."), + _("When non-zero, the process of determining " + "parameter values from function entry point " + "and tail call frames will be printed."), + NULL, + show_entry_values_debug, + &setdebuglist, &showdebuglist); } diff --git a/contrib/gdb-7/gdb/dwarf2loc.h b/contrib/gdb-7/gdb/dwarf2loc.h index da05c98e50..36641b379d 100644 --- a/contrib/gdb-7/gdb/dwarf2loc.h +++ b/contrib/gdb-7/gdb/dwarf2loc.h @@ -1,6 +1,6 @@ /* DWARF 2 location expression support for GDB. - Copyright (C) 2003, 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -20,6 +20,8 @@ #if !defined (DWARF2LOC_H) #define DWARF2LOC_H +#include "dwarf2expr.h" + struct symbol_computed_ops; struct objfile; struct dwarf2_per_cu_data; @@ -31,7 +33,7 @@ struct axs_value; dwarf2read.c and dwarf2loc.c. */ /* `set debug entry-values' setting. */ -extern int entry_values_debug; +extern unsigned int entry_values_debug; /* Return the OBJFILE associated with the compilation unit CU. If CU came from a separate debuginfo file, then the master objfile is @@ -39,7 +41,7 @@ extern int entry_values_debug; struct objfile *dwarf2_per_cu_objfile (struct dwarf2_per_cu_data *cu); /* Return the address size given in the compilation unit header for CU. */ -CORE_ADDR dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *cu); +int dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *cu); /* Return the DW_FORM_ref_addr size given in the compilation unit header for CU. */ @@ -60,12 +62,17 @@ const gdb_byte *dwarf2_find_location_expression size_t *locexpr_length, CORE_ADDR pc); -struct dwarf2_locexpr_baton dwarf2_fetch_die_location_block - (unsigned int offset, struct dwarf2_per_cu_data *per_cu, +struct dwarf2_locexpr_baton dwarf2_fetch_die_loc_sect_off + (sect_offset offset_in_cu, struct dwarf2_per_cu_data *per_cu, + CORE_ADDR (*get_frame_pc) (void *baton), + void *baton); + +struct dwarf2_locexpr_baton dwarf2_fetch_die_loc_cu_off + (cu_offset offset_in_cu, struct dwarf2_per_cu_data *per_cu, CORE_ADDR (*get_frame_pc) (void *baton), void *baton); -struct type *dwarf2_get_die_type (unsigned int die_offset, +struct type *dwarf2_get_die_type (cu_offset die_offset, struct dwarf2_per_cu_data *per_cu); /* Evaluate a location description, starting at DATA and with length @@ -75,9 +82,12 @@ struct type *dwarf2_get_die_type (unsigned int die_offset, struct value *dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame, const gdb_byte *data, - unsigned short size, + size_t size, struct dwarf2_per_cu_data *per_cu); +CORE_ADDR dwarf2_read_addr_index (struct dwarf2_per_cu_data *per_cu, + unsigned int addr_index); + /* The symbol location baton types used by the DWARF-2 reader (i.e. SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol). "struct dwarf2_locexpr_baton" is for a symbol with a single location @@ -92,7 +102,7 @@ struct dwarf2_locexpr_baton /* Length of the location expression. For optimized out expressions it is zero. */ - unsigned long size; + size_t size; /* The compilation unit containing the symbol whose location we're computing. */ @@ -109,11 +119,15 @@ struct dwarf2_loclist_baton const gdb_byte *data; /* Length of the location list. */ - unsigned long size; + size_t size; /* The compilation unit containing the symbol whose location we're computing. */ struct dwarf2_per_cu_data *per_cu; + + /* Non-zero if the location list lives in .debug_loc.dwo. + The format of entries in this section are different. */ + unsigned char from_dwo; }; extern const struct symbol_computed_ops dwarf2_locexpr_funcs; diff --git a/contrib/gdb-7/gdb/dwarf2read.c b/contrib/gdb-7/gdb/dwarf2read.c index 8c81c8a78d..6151b3d515 100644 --- a/contrib/gdb-7/gdb/dwarf2read.c +++ b/contrib/gdb-7/gdb/dwarf2read.c @@ -1,6 +1,6 @@ /* DWARF 2 debugging format support for GDB. - Copyright (C) 1994-2012 Free Software Foundation, Inc. + Copyright (C) 1994-2013 Free Software Foundation, Inc. Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, Inc. with support from Florida State University (under contract @@ -24,8 +24,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +/* FIXME: Various die-reading functions need to be more careful with + reading off the end of the section. + E.g., load_partial_dies, read_partial_die. */ + #include "defs.h" #include "bfd.h" +#include "elf-bfd.h" #include "symtab.h" #include "gdbtypes.h" #include "objfiles.h" @@ -55,79 +60,35 @@ #include "completer.h" #include "vec.h" #include "c-lang.h" +#include "go-lang.h" #include "valprint.h" +#include "gdbcore.h" /* for gnutarget */ +#include "gdb/gdb-index.h" #include +#include "gdb_bfd.h" +#include "f-lang.h" +#include "source.h" #include #include "gdb_string.h" #include "gdb_assert.h" #include -#ifdef HAVE_ZLIB_H -#include -#endif -#ifdef HAVE_MMAP -#include -#ifndef MAP_FAILED -#define MAP_FAILED ((void *) -1) -#endif -#endif typedef struct symbol *symbolp; DEF_VEC_P (symbolp); -#if 0 -/* .debug_info header for a compilation unit - Because of alignment constraints, this structure has padding and cannot - be mapped directly onto the beginning of the .debug_info section. */ -typedef struct comp_unit_header - { - unsigned int length; /* length of the .debug_info - contribution */ - unsigned short version; /* version number -- 2 for DWARF - version 2 */ - unsigned int abbrev_offset; /* offset into .debug_abbrev section */ - unsigned char addr_size; /* byte size of an address -- 4 */ - } -_COMP_UNIT_HEADER; -#define _ACTUAL_COMP_UNIT_HEADER_SIZE 11 -#endif - -/* .debug_line statement program prologue - Because of alignment constraints, this structure has padding and cannot - be mapped directly onto the beginning of the .debug_info section. */ -typedef struct statement_prologue - { - unsigned int total_length; /* byte length of the statement - information */ - unsigned short version; /* version number -- 2 for DWARF - version 2 */ - unsigned int prologue_length; /* # bytes between prologue & - stmt program */ - unsigned char minimum_instruction_length; /* byte size of - smallest instr */ - unsigned char default_is_stmt; /* initial value of is_stmt - register */ - char line_base; - unsigned char line_range; - unsigned char opcode_base; /* number assigned to first special - opcode */ - unsigned char *standard_opcode_lengths; - } -_STATEMENT_PROLOGUE; +/* When non-zero, print basic high level tracing messages. + This is in contrast to the low level DIE reading of dwarf2_die_debug. */ +static int dwarf2_read_debug = 0; /* When non-zero, dump DIEs after they are read in. */ -static int dwarf2_die_debug = 0; +static unsigned int dwarf2_die_debug = 0; /* When non-zero, cross-check physname against demangler. */ static int check_physname = 0; -static int pagesize; - -/* When set, the file that we're processing is known to have debugging - info for C++ namespaces. GCC 3.3.x did not produce this information, - but later versions do. */ - -static int processing_has_namespace_info; +/* When non-zero, do not reject deprecated .gdb_index sections. */ +static int use_deprecated_index_sections = 0; static const struct objfile_data *dwarf2_objfile_data_key; @@ -136,10 +97,6 @@ struct dwarf2_section_info asection *asection; gdb_byte *buffer; bfd_size_type size; - /* Not NULL if the section was actually mmapped. */ - void *map_addr; - /* Page aligned size of mmapped area. */ - bfd_size_type map_len; /* True if we have tried to read this section. */ int readin; }; @@ -153,6 +110,28 @@ typedef uint32_t offset_type; DEF_VEC_I (offset_type); +/* Ensure only legit values are used. */ +#define DW2_GDB_INDEX_SYMBOL_STATIC_SET_VALUE(cu_index, value) \ + do { \ + gdb_assert ((unsigned int) (value) <= 1); \ + GDB_INDEX_SYMBOL_STATIC_SET_VALUE((cu_index), (value)); \ + } while (0) + +/* Ensure only legit values are used. */ +#define DW2_GDB_INDEX_SYMBOL_KIND_SET_VALUE(cu_index, value) \ + do { \ + gdb_assert ((value) >= GDB_INDEX_SYMBOL_KIND_TYPE \ + && (value) <= GDB_INDEX_SYMBOL_KIND_OTHER); \ + GDB_INDEX_SYMBOL_KIND_SET_VALUE((cu_index), (value)); \ + } while (0) + +/* Ensure we don't use more than the alloted nuber of bits for the CU. */ +#define DW2_GDB_INDEX_CU_SET_VALUE(cu_index, value) \ + do { \ + gdb_assert (((value) & ~GDB_INDEX_CU_MASK) == 0); \ + GDB_INDEX_CU_SET_VALUE((cu_index), (value)); \ + } while (0) + /* A description of the mapped index. The file format is described in a comment by the code that writes the index. */ struct mapped_index @@ -179,6 +158,12 @@ struct mapped_index const char *constant_pool; }; +typedef struct dwarf2_per_cu_data *dwarf2_per_cu_ptr; +DEF_VEC_P (dwarf2_per_cu_ptr); + +/* Collection of data recorded per objfile. + This hangs off of dwarf2_objfile_data_key. */ + struct dwarf2_per_objfile { struct dwarf2_section_info info; @@ -189,6 +174,7 @@ struct dwarf2_per_objfile struct dwarf2_section_info macro; struct dwarf2_section_info str; struct dwarf2_section_info ranges; + struct dwarf2_section_info addr; struct dwarf2_section_info frame; struct dwarf2_section_info eh_frame; struct dwarf2_section_info gdb_index; @@ -198,7 +184,7 @@ struct dwarf2_per_objfile /* Back link. */ struct objfile *objfile; - /* A list of all the compilation units. This is used to locate + /* Table of all the compilation units. This is used to locate the target compilation unit of a particular reference. */ struct dwarf2_per_cu_data **all_comp_units; @@ -206,19 +192,54 @@ struct dwarf2_per_objfile int n_comp_units; /* The number of .debug_types-related CUs. */ - int n_type_comp_units; + int n_type_units; - /* The .debug_types-related CUs. */ - struct dwarf2_per_cu_data **type_comp_units; + /* The .debug_types-related CUs (TUs). */ + struct signatured_type **all_type_units; - /* A chain of compilation units that are currently read in, so that - they can be freed later. */ - struct dwarf2_per_cu_data *read_in_chain; + /* The number of entries in all_type_unit_groups. */ + int n_type_unit_groups; + + /* Table of type unit groups. + This exists to make it easy to iterate over all CUs and TU groups. */ + struct type_unit_group **all_type_unit_groups; + + /* Table of struct type_unit_group objects. + The hash key is the DW_AT_stmt_list value. */ + htab_t type_unit_groups; /* A table mapping .debug_types signatures to its signatured_type entry. This is NULL if the .debug_types section hasn't been read in yet. */ htab_t signatured_types; + /* Type unit statistics, to see how well the scaling improvements + are doing. */ + struct tu_stats + { + int nr_uniq_abbrev_tables; + int nr_symtabs; + int nr_symtab_sharers; + int nr_stmt_less_type_units; + } tu_stats; + + /* A chain of compilation units that are currently read in, so that + they can be freed later. */ + struct dwarf2_per_cu_data *read_in_chain; + + /* A table mapping DW_AT_dwo_name values to struct dwo_file objects. + This is NULL if the table hasn't been allocated yet. */ + htab_t dwo_files; + + /* Non-zero if we've check for whether there is a DWP file. */ + int dwp_checked; + + /* The DWP file if there is one, or NULL. */ + struct dwp_file *dwp_file; + + /* The shared '.dwz' file, if one exists. This is used when the + original data was compressed using 'dwz -m'. */ + struct dwz_file *dwz_file; + /* A flag indicating wether this objfile has a section loaded at a VMA of 0. */ int has_section_at_zero; @@ -231,24 +252,25 @@ struct dwarf2_per_objfile struct mapped_index *index_table; /* When using index_table, this keeps track of all quick_file_names entries. - TUs can share line table entries with CUs or other TUs, and there can be - a lot more TUs than unique line tables, so we maintain a separate table - of all line table entries to support the sharing. */ + TUs typically share line table entries with a CU, so we maintain a + separate table of all line table entries to support the sharing. + Note that while there can be way more TUs than CUs, we've already + sorted all the TUs into "type unit groups", grouped by their + DW_AT_stmt_list value. Therefore the only sharing done here is with a + CU and its associated TU group if there is one. */ htab_t quick_file_names_table; /* Set during partial symbol reading, to prevent queueing of full symbols. */ int reading_partial_symbols; - /* Table mapping type .debug_info DIE offsets to types. + /* Table mapping type DIEs to their struct type *. This is NULL if not allocated yet. - It (currently) makes sense to allocate debug_types_type_hash lazily. - To keep things simple we allocate both lazily. */ - htab_t debug_info_type_hash; + The mapping is done via (CU/TU signature + DIE offset) -> type. */ + htab_t die_type_hash; - /* Table mapping type .debug_types DIE offsets to types. - This is NULL if not allocated yet. */ - htab_t debug_types_type_hash; + /* The CUs we recently read. */ + VEC (dwarf2_per_cu_ptr) *just_read_cus; }; static struct dwarf2_per_objfile *dwarf2_per_objfile; @@ -258,7 +280,8 @@ static struct dwarf2_per_objfile *dwarf2_per_objfile; /* Note that if the debugging section has been compressed, it might have a name like .zdebug_info. */ -static const struct dwarf2_debug_sections dwarf2_elf_names = { +static const struct dwarf2_debug_sections dwarf2_elf_names = +{ { ".debug_info", ".zdebug_info" }, { ".debug_abbrev", ".zdebug_abbrev" }, { ".debug_line", ".zdebug_line" }, @@ -268,18 +291,45 @@ static const struct dwarf2_debug_sections dwarf2_elf_names = { { ".debug_str", ".zdebug_str" }, { ".debug_ranges", ".zdebug_ranges" }, { ".debug_types", ".zdebug_types" }, + { ".debug_addr", ".zdebug_addr" }, { ".debug_frame", ".zdebug_frame" }, { ".eh_frame", NULL }, { ".gdb_index", ".zgdb_index" }, 23 }; -/* local data types */ +/* List of DWO/DWP sections. */ + +static const struct dwop_section_names +{ + struct dwarf2_section_names abbrev_dwo; + struct dwarf2_section_names info_dwo; + struct dwarf2_section_names line_dwo; + struct dwarf2_section_names loc_dwo; + struct dwarf2_section_names macinfo_dwo; + struct dwarf2_section_names macro_dwo; + struct dwarf2_section_names str_dwo; + struct dwarf2_section_names str_offsets_dwo; + struct dwarf2_section_names types_dwo; + struct dwarf2_section_names cu_index; + struct dwarf2_section_names tu_index; +} +dwop_section_names = +{ + { ".debug_abbrev.dwo", ".zdebug_abbrev.dwo" }, + { ".debug_info.dwo", ".zdebug_info.dwo" }, + { ".debug_line.dwo", ".zdebug_line.dwo" }, + { ".debug_loc.dwo", ".zdebug_loc.dwo" }, + { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo" }, + { ".debug_macro.dwo", ".zdebug_macro.dwo" }, + { ".debug_str.dwo", ".zdebug_str.dwo" }, + { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo" }, + { ".debug_types.dwo", ".zdebug_types.dwo" }, + { ".debug_cu_index", ".zdebug_cu_index" }, + { ".debug_tu_index", ".zdebug_tu_index" }, +}; -/* We hold several abbreviation tables in memory at the same time. */ -#ifndef ABBREV_HASH_SIZE -#define ABBREV_HASH_SIZE 121 -#endif +/* local data types */ /* The data in a compilation unit header, after target2host translation, looks like this. */ @@ -289,7 +339,7 @@ struct comp_unit_head short version; unsigned char addr_size; unsigned char signed_addr_p; - unsigned int abbrev_offset; + sect_offset abbrev_offset; /* Size of file offsets; either 4 or 8. */ unsigned int offset_size; @@ -299,11 +349,11 @@ struct comp_unit_head /* Offset to the first byte of this compilation unit header in the .debug_info section, for resolving relative reference dies. */ - unsigned int offset; + sect_offset offset; /* Offset to first die in this cu from the start of the cu. This will be the first byte following the compilation unit header. */ - unsigned int first_die_offset; + cu_offset first_die_offset; }; /* Type used for delaying computation of method physnames. @@ -344,8 +394,6 @@ struct dwarf2_cu /* Non-zero if base_address has been set. */ int base_known; - struct function_range *first_fn, *last_fn, *cached_fn; - /* The language we are debugging. */ enum language language; const struct language_defn *language_defn; @@ -363,13 +411,13 @@ struct dwarf2_cu distinguish these in buildsym.c. */ struct pending **list_in_scope; - /* DWARF abbreviation table associated with this compilation unit. */ - struct abbrev_info **dwarf2_abbrevs; - - /* Storage for the abbrev table. */ - struct obstack abbrev_obstack; + /* The abbrev table for this CU. + Normally this points to the abbrev table in the objfile. + But if DWO_UNIT is non-NULL this is the abbrev table in the DWO file. */ + struct abbrev_table *abbrev_table; - /* Hash table holding all the loaded partial DIEs. */ + /* Hash table holding all the loaded partial DIEs + with partial_die->offset.SECT_OFF as hash. */ htab_t partial_dies; /* Storage for things with the same lifetime as this read-in compilation @@ -388,7 +436,8 @@ struct dwarf2_cu /* How many compilation units ago was this CU last referenced? */ int last_used; - /* A hash table of die offsets for following references. */ + /* A hash table of DIE cu_offset for following references with + die_info->offset.sect_off as hash. */ htab_t die_hash; /* Full DIEs if read in. */ @@ -409,62 +458,101 @@ struct dwarf2_cu /* To be copied to symtab->call_site_htab. */ htab_t call_site_htab; + /* Non-NULL if this CU came from a DWO file. + There is an invariant here that is important to remember: + Except for attributes copied from the top level DIE in the "main" + (or "stub") file in preparation for reading the DWO file + (e.g., DW_AT_GNU_addr_base), we KISS: there is only *one* CU. + Either there isn't a DWO file (in which case this is NULL and the point + is moot), or there is and either we're not going to read it (in which + case this is NULL) or there is and we are reading it (in which case this + is non-NULL). */ + struct dwo_unit *dwo_unit; + + /* The DW_AT_addr_base attribute if present, zero otherwise + (zero is a valid value though). + Note this value comes from the stub CU/TU's DIE. */ + ULONGEST addr_base; + + /* The DW_AT_ranges_base attribute if present, zero otherwise + (zero is a valid value though). + Note this value comes from the stub CU/TU's DIE. + Also note that the value is zero in the non-DWO case so this value can + be used without needing to know whether DWO files are in use or not. + N.B. This does not apply to DW_AT_ranges appearing in + DW_TAG_compile_unit dies. This is a bit of a wart, consider if ever + DW_AT_ranges appeared in the DW_TAG_compile_unit of DWO DIEs: then + DW_AT_ranges_base *would* have to be applied, and we'd have to care + whether the DW_AT_ranges attribute came from the skeleton or DWO. */ + ULONGEST ranges_base; + /* Mark used when releasing cached dies. */ unsigned int mark : 1; - /* This flag will be set if this compilation unit might include - inter-compilation-unit references. */ - unsigned int has_form_ref_addr : 1; - - /* This flag will be set if this compilation unit includes any - DW_TAG_namespace DIEs. If we know that there are explicit - DIEs for namespaces, we don't need to try to infer them - from mangled names. */ - unsigned int has_namespace_info : 1; - /* This CU references .debug_loc. See the symtab->locations_valid field. This test is imperfect as there may exist optimized debug code not using any location list and still facing inlining issues if handled as unoptimized code. For a future better test see GCC PR other/32998. */ - unsigned int has_loclist : 1; + + /* These cache the results for producer_is_* fields. CHECKED_PRODUCER is set + if all the producer_is_* fields are valid. This information is cached + because profiling CU expansion showed excessive time spent in + producer_is_gxx_lt_4_6. */ + unsigned int checked_producer : 1; + unsigned int producer_is_gxx_lt_4_6 : 1; + unsigned int producer_is_gcc_lt_4_3 : 1; + unsigned int producer_is_icc : 1; + + /* When set, the file that we're processing is known to have + debugging info for C++ namespaces. GCC 3.3.x did not produce + this information, but later versions do. */ + + unsigned int processing_has_namespace_info : 1; }; /* Persistent data held for a compilation unit, even when not processing it. We put a pointer to this structure in the - read_symtab_private field of the psymtab. If we encounter - inter-compilation-unit references, we also maintain a sorted - list of all compilation units. */ + read_symtab_private field of the psymtab. */ struct dwarf2_per_cu_data { - /* The start offset and length of this compilation unit. 2**29-1 - bytes should suffice to store the length of any compilation unit - - if it doesn't, GDB will fall over anyway. + /* The start offset and length of this compilation unit. NOTE: Unlike comp_unit_head.length, this length includes - initial_length_size. */ - unsigned int offset; - unsigned int length : 29; + initial_length_size. + If the DIE refers to a DWO file, this is always of the original die, + not the DWO file. */ + sect_offset offset; + unsigned int length; /* Flag indicating this compilation unit will be read in before any of the current compilation units are processed. */ unsigned int queued : 1; - /* This flag will be set if we need to load absolutely all DIEs - for this compilation unit, instead of just the ones we think - are interesting. It gets set if we look for a DIE in the + /* This flag will be set when reading partial DIEs if we need to load + absolutely all DIEs for this compilation unit, instead of just the ones + we think are interesting. It gets set if we look for a DIE in the hash table and don't find it. */ unsigned int load_all_dies : 1; - /* Non-null if this CU is from .debug_types; in which case it points - to the section. Otherwise it's from .debug_info. */ - struct dwarf2_section_info *debug_types_section; + /* Non-zero if this CU is from .debug_types. */ + unsigned int is_debug_types : 1; + + /* Non-zero if this CU is from the .dwz file. */ + unsigned int is_dwz : 1; + + /* The section this CU/TU lives in. + If the DIE refers to a DWO file, this is always the original die, + not the DWO file. */ + struct dwarf2_section_info *info_or_types_section; /* Set to non-NULL iff this CU is currently loaded. When it gets freed out of the CU cache it gets reset to NULL again. */ struct dwarf2_cu *cu; - /* The corresponding objfile. */ + /* The corresponding objfile. + Normally we can get the objfile from dwarf2_per_objfile. + However we can enter this file with just a "per_cu" handle. */ struct objfile *objfile; /* When using partial symbol tables, the 'psymtab' field is active. @@ -472,47 +560,301 @@ struct dwarf2_per_cu_data union { /* The partial symbol table associated with this compilation unit, - or NULL for partial units (which do not have an associated - symtab). */ + or NULL for unread partial units. */ struct partial_symtab *psymtab; /* Data needed by the "quick" functions. */ struct dwarf2_per_cu_quick_data *quick; } v; + + /* The CUs we import using DW_TAG_imported_unit. This is filled in + while reading psymtabs, used to compute the psymtab dependencies, + and then cleared. Then it is filled in again while reading full + symbols, and only deleted when the objfile is destroyed. + + This is also used to work around a difference between the way gold + generates .gdb_index version <=7 and the way gdb does. Arguably this + is a gold bug. For symbols coming from TUs, gold records in the index + the CU that includes the TU instead of the TU itself. This breaks + dw2_lookup_symbol: It assumes that if the index says symbol X lives + in CU/TU Y, then one need only expand Y and a subsequent lookup in Y + will find X. Alas TUs live in their own symtab, so after expanding CU Y + we need to look in TU Z to find X. Fortunately, this is akin to + DW_TAG_imported_unit, so we just use the same mechanism: For + .gdb_index version <=7 this also records the TUs that the CU referred + to. Concurrently with this change gdb was modified to emit version 8 + indices so we only pay a price for gold generated indices. */ + VEC (dwarf2_per_cu_ptr) *imported_symtabs; + + /* Type units are grouped by their DW_AT_stmt_list entry so that they + can share them. If this is a TU, this points to the containing + symtab. */ + struct type_unit_group *type_unit_group; }; /* Entry in the signatured_types hash table. */ struct signatured_type { + /* The "per_cu" object of this type. + N.B.: This is the first member so that it's easy to convert pointers + between them. */ + struct dwarf2_per_cu_data per_cu; + + /* The type's signature. */ ULONGEST signature; - /* Offset in .debug_types of the type defined by this TU. */ - unsigned int type_offset; + /* Offset in the TU of the type's DIE, as read from the TU header. + If the definition lives in a DWO file, this value is unusable. */ + cu_offset type_offset_in_tu; + + /* Offset in the section of the type's DIE. + If the definition lives in a DWO file, this is the offset in the + .debug_types.dwo section. + The value is zero until the actual value is known. + Zero is otherwise not a valid section offset. */ + sect_offset type_offset_in_section; +}; + +/* A struct that can be used as a hash key for tables based on DW_AT_stmt_list. + This includes type_unit_group and quick_file_names. */ + +struct stmt_list_hash +{ + /* The DWO unit this table is from or NULL if there is none. */ + struct dwo_unit *dwo_unit; + + /* Offset in .debug_line or .debug_line.dwo. */ + sect_offset line_offset; +}; + +/* Each element of dwarf2_per_objfile->type_unit_groups is a pointer to + an object of this type. */ - /* The CU(/TU) of this type. */ +struct type_unit_group +{ + /* dwarf2read.c's main "handle" on the symtab. + To simplify things we create an artificial CU that "includes" all the + type units using this stmt_list so that the rest of the code still has + a "per_cu" handle on the symtab. + This PER_CU is recognized by having no section. */ +#define IS_TYPE_UNIT_GROUP(per_cu) ((per_cu)->info_or_types_section == NULL) struct dwarf2_per_cu_data per_cu; + + union + { + /* The TUs that share this DW_AT_stmt_list entry. + This is added to while parsing type units to build partial symtabs, + and is deleted afterwards and not used again. */ + VEC (dwarf2_per_cu_ptr) *tus; + + /* When reading the line table in "quick" functions, we need a real TU. + Any will do, we know they all share the same DW_AT_stmt_list entry. + For simplicity's sake, we pick the first one. */ + struct dwarf2_per_cu_data *first_tu; + } t; + + /* The primary symtab. + Type units in a group needn't all be defined in the same source file, + so we create an essentially anonymous symtab as the primary symtab. */ + struct symtab *primary_symtab; + + /* The data used to construct the hash key. */ + struct stmt_list_hash hash; + + /* The number of symtabs from the line header. + The value here must match line_header.num_file_names. */ + unsigned int num_symtabs; + + /* The symbol tables for this TU (obtained from the files listed in + DW_AT_stmt_list). + WARNING: The order of entries here must match the order of entries + in the line header. After the first TU using this type_unit_group, the + line header for the subsequent TUs is recreated from this. This is done + because we need to use the same symtabs for each TU using the same + DW_AT_stmt_list value. Also note that symtabs may be repeated here, + there's no guarantee the line header doesn't have duplicate entries. */ + struct symtab **symtabs; +}; + +/* These sections are what may appear in a DWO file. */ + +struct dwo_sections +{ + struct dwarf2_section_info abbrev; + struct dwarf2_section_info line; + struct dwarf2_section_info loc; + struct dwarf2_section_info macinfo; + struct dwarf2_section_info macro; + struct dwarf2_section_info str; + struct dwarf2_section_info str_offsets; + /* In the case of a virtual DWO file, these two are unused. */ + struct dwarf2_section_info info; + VEC (dwarf2_section_info_def) *types; +}; + +/* Common bits of DWO CUs/TUs. */ + +struct dwo_unit +{ + /* Backlink to the containing struct dwo_file. */ + struct dwo_file *dwo_file; + + /* The "id" that distinguishes this CU/TU. + .debug_info calls this "dwo_id", .debug_types calls this "signature". + Since signatures came first, we stick with it for consistency. */ + ULONGEST signature; + + /* The section this CU/TU lives in, in the DWO file. */ + struct dwarf2_section_info *info_or_types_section; + + /* Same as dwarf2_per_cu_data:{offset,length} but for the DWO section. */ + sect_offset offset; + unsigned int length; + + /* For types, offset in the type's DIE of the type defined by this TU. */ + cu_offset type_offset_in_tu; +}; + +/* Data for one DWO file. + This includes virtual DWO files that have been packaged into a + DWP file. */ + +struct dwo_file +{ + /* The DW_AT_GNU_dwo_name attribute. This is the hash key. + For virtual DWO files the name is constructed from the section offsets + of abbrev,line,loc,str_offsets so that we combine virtual DWO files + from related CU+TUs. */ + const char *name; + + /* The bfd, when the file is open. Otherwise this is NULL. + This is unused(NULL) for virtual DWO files where we use dwp_file.dbfd. */ + bfd *dbfd; + + /* Section info for this file. */ + struct dwo_sections sections; + + /* Table of CUs in the file. + Each element is a struct dwo_unit. */ + htab_t cus; + + /* Table of TUs in the file. + Each element is a struct dwo_unit. */ + htab_t tus; +}; + +/* These sections are what may appear in a DWP file. */ + +struct dwp_sections +{ + struct dwarf2_section_info str; + struct dwarf2_section_info cu_index; + struct dwarf2_section_info tu_index; + /* The .debug_info.dwo, .debug_types.dwo, and other sections are referenced + by section number. We don't need to record them here. */ +}; + +/* These sections are what may appear in a virtual DWO file. */ + +struct virtual_dwo_sections +{ + struct dwarf2_section_info abbrev; + struct dwarf2_section_info line; + struct dwarf2_section_info loc; + struct dwarf2_section_info macinfo; + struct dwarf2_section_info macro; + struct dwarf2_section_info str_offsets; + /* Each DWP hash table entry records one CU or one TU. + That is recorded here, and copied to dwo_unit.info_or_types_section. */ + struct dwarf2_section_info info_or_types; +}; + +/* Contents of DWP hash tables. */ + +struct dwp_hash_table +{ + uint32_t nr_units, nr_slots; + const gdb_byte *hash_table, *unit_table, *section_pool; +}; + +/* Data for one DWP file. */ + +struct dwp_file +{ + /* Name of the file. */ + const char *name; + + /* The bfd, when the file is open. Otherwise this is NULL. */ + bfd *dbfd; + + /* Section info for this file. */ + struct dwp_sections sections; + + /* Table of CUs in the file. */ + const struct dwp_hash_table *cus; + + /* Table of TUs in the file. */ + const struct dwp_hash_table *tus; + + /* Table of loaded CUs/TUs. Each entry is a struct dwo_unit *. */ + htab_t loaded_cutus; + + /* Table to map ELF section numbers to their sections. */ + unsigned int num_sections; + asection **elf_sections; +}; + +/* This represents a '.dwz' file. */ + +struct dwz_file +{ + /* A dwz file can only contain a few sections. */ + struct dwarf2_section_info abbrev; + struct dwarf2_section_info info; + struct dwarf2_section_info str; + struct dwarf2_section_info line; + struct dwarf2_section_info macro; + struct dwarf2_section_info gdb_index; + + /* The dwz's BFD. */ + bfd *dwz_bfd; }; /* Struct used to pass misc. parameters to read_die_and_children, et al. which are used for both .debug_info and .debug_types dies. All parameters here are unchanging for the life of the call. This - struct exists to abstract away the constant parameters of die - reading. */ + struct exists to abstract away the constant parameters of die reading. */ struct die_reader_specs { - /* The bfd of this objfile. */ + /* die_section->asection->owner. */ bfd* abfd; /* The CU of the DIE we are parsing. */ struct dwarf2_cu *cu; - /* Pointer to start of section buffer. - This is either the start of .debug_info or .debug_types. */ - const gdb_byte *buffer; + /* Non-NULL if reading a DWO file (including one packaged into a DWP). */ + struct dwo_file *dwo_file; + + /* The section the die comes from. + This is either .debug_info or .debug_types, or the .dwo variants. */ + struct dwarf2_section_info *die_section; + + /* die_section->buffer. */ + gdb_byte *buffer; + + /* The end of the buffer. */ + const gdb_byte *buffer_end; }; +/* Type of function passed to init_cutu_and_read_dies, et.al. */ +typedef void (die_reader_func_ftype) (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data); + /* The line number information for a compilation unit (found in the .debug_line section) begins with a "statement program header", which contains the following information. */ @@ -565,7 +907,7 @@ struct line_header struct partial_die_info { /* Offset of this DIE. */ - unsigned int offset; + sect_offset offset; /* DWARF-2 tag for this DIE. */ ENUM_BITFIELD(dwarf_tag) tag : 16; @@ -577,6 +919,7 @@ struct partial_die_info unsigned int has_type : 1; unsigned int has_specification : 1; unsigned int has_pc_info : 1; + unsigned int may_be_inlined : 1; /* Flag set if the SCOPE field of this structure has been computed. */ @@ -591,9 +934,15 @@ struct partial_die_info /* Flag set if fixup_partial_die has been called on this die. */ unsigned int fixup_called : 1; + /* Flag set if DW_TAG_imported_unit uses DW_FORM_GNU_ref_alt. */ + unsigned int is_dwz : 1; + + /* Flag set if spec_offset uses DW_FORM_GNU_ref_alt. */ + unsigned int spec_is_dwz : 1; + /* The name of this DIE. Normally the value of DW_AT_name, but sometimes a default name for unnamed DIEs. */ - char *name; + const char *name; /* The linkage name, if present. */ const char *linkage_name; @@ -601,10 +950,17 @@ struct partial_die_info /* The scope to prepend to our children. This is generally allocated on the comp_unit_obstack, so will disappear when this compilation unit leaves the cache. */ - char *scope; + const char *scope; - /* The location description associated with this DIE, if any. */ - struct dwarf_block *locdesc; + /* Some data associated with the partial DIE. The tag determines + which field is live. */ + union + { + /* The location description associated with this DIE, if any. */ + struct dwarf_block *locdesc; + /* The offset of an import, for DW_TAG_imported_unit. */ + sect_offset offset; + } d; /* If HAS_PC_INFO, the PC range associated with this DIE. */ CORE_ADDR lowpc; @@ -619,7 +975,7 @@ struct partial_die_info /* If HAS_SPECIFICATION, the offset of the DIE referred to by DW_AT_specification (or DW_AT_abstract_origin or DW_AT_extension). */ - unsigned int spec_offset; + sect_offset spec_offset; /* Pointers to this DIE's parent, first child, and next sibling, if any. */ @@ -643,6 +999,27 @@ struct attr_abbrev ENUM_BITFIELD(dwarf_form) form : 16; }; +/* Size of abbrev_table.abbrev_hash_table. */ +#define ABBREV_HASH_SIZE 121 + +/* Top level data structure to contain an abbreviation table. */ + +struct abbrev_table +{ + /* Where the abbrev table came from. + This is used as a sanity check when the table is used. */ + sect_offset offset; + + /* Storage for the abbrev table. */ + struct obstack abbrev_obstack; + + /* Hash table of abbrevs. + This is an array of size ABBREV_HASH_SIZE allocated in abbrev_obstack. + It could be statically allocated, but the previous code didn't so we + don't either. */ + struct abbrev_info **abbrevs; +}; + /* Attributes have a name and a value. */ struct attribute { @@ -656,7 +1033,7 @@ struct attribute union { - char *str; + const char *str; struct dwarf_block *blk; ULONGEST unsnd; LONGEST snd; @@ -683,7 +1060,7 @@ struct die_info unsigned int abbrev; /* Offset in .debug_info or .debug_types section. */ - unsigned int offset; + sect_offset offset; /* The dies in a compilation unit form an n-ary tree. PARENT points to this die's parent; CHILD points to the first child of @@ -699,14 +1076,6 @@ struct die_info struct attribute attrs[1]; }; -struct function_range -{ - const char *name; - CORE_ADDR lowpc, highpc; - int seen_line; - struct function_range *next; -}; - /* Get at parts of an attribute structure. */ #define DW_STRING(attr) ((attr)->u.str) @@ -720,7 +1089,7 @@ struct function_range /* Blocks are a bunch of untyped bytes. */ struct dwarf_block { - unsigned int size; + size_t size; /* Valid only if SIZE is not zero. */ gdb_byte *data; @@ -778,7 +1147,7 @@ struct field_info to the head of the member function field chain. */ struct fnfieldlist { - char *name; + const char *name; int length; struct nextfnfield *head; } @@ -803,6 +1172,7 @@ struct field_info struct dwarf2_queue_item { struct dwarf2_per_cu_data *per_cu; + enum language pretend_language; struct dwarf2_queue_item *next; }; @@ -865,11 +1235,13 @@ dwarf2_const_value_length_mismatch_complaint (const char *arg1, int arg2, } static void -dwarf2_macros_too_long_complaint (struct dwarf2_section_info *section) +dwarf2_section_buffer_overflow_complaint (struct dwarf2_section_info *section) { complaint (&symfile_complaints, - _("macro info runs off end of `%s' section"), - section->asection->name); + _("debug info runs off end of %s section" + " [in module %s]"), + section->asection->name, + bfd_get_filename (section->asection->owner)); } static void @@ -923,57 +1295,56 @@ static void add_partial_subprogram (struct partial_die_info *pdi, CORE_ADDR *lowpc, CORE_ADDR *highpc, int need_pc, struct dwarf2_cu *cu); -static gdb_byte *locate_pdi_sibling (struct partial_die_info *orig_pdi, - gdb_byte *buffer, gdb_byte *info_ptr, - bfd *abfd, struct dwarf2_cu *cu); - -static void dwarf2_psymtab_to_symtab (struct partial_symtab *); +static void dwarf2_read_symtab (struct partial_symtab *, + struct objfile *); static void psymtab_to_symtab_1 (struct partial_symtab *); -static void dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu); +static struct abbrev_info *abbrev_table_lookup_abbrev + (const struct abbrev_table *, unsigned int); -static void dwarf2_free_abbrev_table (void *); +static struct abbrev_table *abbrev_table_read_table + (struct dwarf2_section_info *, sect_offset); -static unsigned int peek_abbrev_code (bfd *, gdb_byte *); +static void abbrev_table_free (struct abbrev_table *); + +static void abbrev_table_free_cleanup (void *); -static struct abbrev_info *peek_die_abbrev (gdb_byte *, unsigned int *, - struct dwarf2_cu *); +static void dwarf2_read_abbrevs (struct dwarf2_cu *, + struct dwarf2_section_info *); + +static void dwarf2_free_abbrev_table (void *); -static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int, - struct dwarf2_cu *); +static unsigned int peek_abbrev_code (bfd *, gdb_byte *); -static struct partial_die_info *load_partial_dies (bfd *, - gdb_byte *, gdb_byte *, - int, struct dwarf2_cu *); +static struct partial_die_info *load_partial_dies + (const struct die_reader_specs *, gdb_byte *, int); -static gdb_byte *read_partial_die (struct partial_die_info *, - struct abbrev_info *abbrev, - unsigned int, bfd *, - gdb_byte *, gdb_byte *, - struct dwarf2_cu *); +static gdb_byte *read_partial_die (const struct die_reader_specs *, + struct partial_die_info *, + struct abbrev_info *, + unsigned int, + gdb_byte *); -static struct partial_die_info *find_partial_die (unsigned int, +static struct partial_die_info *find_partial_die (sect_offset, int, struct dwarf2_cu *); static void fixup_partial_die (struct partial_die_info *, struct dwarf2_cu *); -static gdb_byte *read_attribute (struct attribute *, struct attr_abbrev *, - bfd *, gdb_byte *, struct dwarf2_cu *); - -static gdb_byte *read_attribute_value (struct attribute *, unsigned, - bfd *, gdb_byte *, struct dwarf2_cu *); +static gdb_byte *read_attribute (const struct die_reader_specs *, + struct attribute *, struct attr_abbrev *, + gdb_byte *); -static unsigned int read_1_byte (bfd *, gdb_byte *); +static unsigned int read_1_byte (bfd *, const gdb_byte *); -static int read_1_signed_byte (bfd *, gdb_byte *); +static int read_1_signed_byte (bfd *, const gdb_byte *); -static unsigned int read_2_bytes (bfd *, gdb_byte *); +static unsigned int read_2_bytes (bfd *, const gdb_byte *); -static unsigned int read_4_bytes (bfd *, gdb_byte *); +static unsigned int read_4_bytes (bfd *, const gdb_byte *); -static ULONGEST read_8_bytes (bfd *, gdb_byte *); +static ULONGEST read_8_bytes (bfd *, const gdb_byte *); static CORE_ADDR read_address (bfd *, gdb_byte *ptr, struct dwarf2_cu *, unsigned int *); @@ -989,6 +1360,9 @@ static LONGEST read_offset (bfd *, gdb_byte *, const struct comp_unit_head *, static LONGEST read_offset_1 (bfd *, gdb_byte *, unsigned int); +static sect_offset read_abbrev_offset (struct dwarf2_section_info *, + sect_offset); + static gdb_byte *read_n_bytes (bfd *, gdb_byte *, unsigned int); static char *read_direct_string (bfd *, gdb_byte *, unsigned int *); @@ -997,11 +1371,17 @@ static char *read_indirect_string (bfd *, gdb_byte *, const struct comp_unit_head *, unsigned int *); -static unsigned long read_unsigned_leb128 (bfd *, gdb_byte *, unsigned int *); +static char *read_indirect_string_from_dwz (struct dwz_file *, LONGEST); + +static ULONGEST read_unsigned_leb128 (bfd *, gdb_byte *, unsigned int *); -static long read_signed_leb128 (bfd *, gdb_byte *, unsigned int *); +static LONGEST read_signed_leb128 (bfd *, gdb_byte *, unsigned int *); -static gdb_byte *skip_leb128 (bfd *, gdb_byte *); +static CORE_ADDR read_addr_index_from_leb128 (struct dwarf2_cu *, gdb_byte *, + unsigned int *); + +static char *read_str_index (const struct die_reader_specs *reader, + struct dwarf2_cu *cu, ULONGEST str_index); static void set_cu_language (unsigned int, struct dwarf2_cu *); @@ -1009,8 +1389,7 @@ static struct attribute *dwarf2_attr (struct die_info *, unsigned int, struct dwarf2_cu *); static struct attribute *dwarf2_attr_no_follow (struct die_info *, - unsigned int, - struct dwarf2_cu *); + unsigned int); static int dwarf2_flag_true_p (struct die_info *die, unsigned name, struct dwarf2_cu *cu); @@ -1025,9 +1404,8 @@ static void free_line_header (struct line_header *lh); static void add_file_name (struct line_header *, char *, unsigned int, unsigned int, unsigned int); -static struct line_header *(dwarf_decode_line_header - (unsigned int offset, - bfd *abfd, struct dwarf2_cu *cu)); +static struct line_header *dwarf_decode_line_header (unsigned int offset, + struct dwarf2_cu *cu); static void dwarf_decode_lines (struct line_header *, const char *, struct dwarf2_cu *, struct partial_symtab *, @@ -1035,6 +1413,9 @@ static void dwarf_decode_lines (struct line_header *, const char *, static void dwarf2_start_subfile (char *, const char *, const char *); +static void dwarf2_start_symtab (struct dwarf2_cu *, + const char *, const char *, CORE_ADDR); + static struct symbol *new_symbol (struct die_info *, struct type *, struct dwarf2_cu *); @@ -1048,7 +1429,7 @@ static void dwarf2_const_value_attr (struct attribute *attr, struct type *type, const char *name, struct obstack *obstack, - struct dwarf2_cu *cu, long *value, + struct dwarf2_cu *cu, LONGEST *value, gdb_byte **bytes, struct dwarf2_locexpr_baton **baton); @@ -1072,7 +1453,7 @@ static struct type *read_type_die (struct die_info *, struct dwarf2_cu *); static struct type *read_type_die_1 (struct die_info *, struct dwarf2_cu *); -static char *determine_prefix (struct die_info *die, struct dwarf2_cu *); +static const char *determine_prefix (struct die_info *die, struct dwarf2_cu *); static char *typename_concat (struct obstack *obs, const char *prefix, const char *suffix, int physname, @@ -1139,54 +1520,45 @@ static CORE_ADDR decode_locdesc (struct dwarf_block *, struct dwarf2_cu *); static enum dwarf_array_dim_ordering read_array_order (struct die_info *, struct dwarf2_cu *); -static struct die_info *read_comp_unit (gdb_byte *, struct dwarf2_cu *); - -static struct die_info *read_die_and_children_1 (const struct die_reader_specs *reader, - gdb_byte *info_ptr, - gdb_byte **new_info_ptr, - struct die_info *parent); - -static struct die_info *read_die_and_children (const struct die_reader_specs *reader, +static struct die_info *read_die_and_children (const struct die_reader_specs *, gdb_byte *info_ptr, gdb_byte **new_info_ptr, struct die_info *parent); -static struct die_info *read_die_and_siblings (const struct die_reader_specs *reader, +static struct die_info *read_die_and_siblings (const struct die_reader_specs *, gdb_byte *info_ptr, gdb_byte **new_info_ptr, struct die_info *parent); -static gdb_byte *read_full_die (const struct die_reader_specs *reader, - struct die_info **, gdb_byte *, - int *); +static gdb_byte *read_full_die_1 (const struct die_reader_specs *, + struct die_info **, gdb_byte *, int *, int); + +static gdb_byte *read_full_die (const struct die_reader_specs *, + struct die_info **, gdb_byte *, int *); static void process_die (struct die_info *, struct dwarf2_cu *); -static char *dwarf2_canonicalize_name (char *, struct dwarf2_cu *, - struct obstack *); +static const char *dwarf2_canonicalize_name (const char *, struct dwarf2_cu *, + struct obstack *); -static char *dwarf2_name (struct die_info *die, struct dwarf2_cu *); +static const char *dwarf2_name (struct die_info *die, struct dwarf2_cu *); -static const char *dwarf2_full_name (char *name, +static const char *dwarf2_full_name (const char *name, struct die_info *die, struct dwarf2_cu *cu); static struct die_info *dwarf2_extension (struct die_info *die, struct dwarf2_cu **); -static char *dwarf_tag_name (unsigned int); +static const char *dwarf_tag_name (unsigned int); -static char *dwarf_attr_name (unsigned int); +static const char *dwarf_attr_name (unsigned int); -static char *dwarf_form_name (unsigned int); +static const char *dwarf_form_name (unsigned int); static char *dwarf_bool_name (unsigned int); -static char *dwarf_type_encoding_name (unsigned int); - -#if 0 -static char *dwarf_cfi_name (unsigned int); -#endif +static const char *dwarf_type_encoding_name (unsigned int); static struct die_info *sibling_die (struct die_info *); @@ -1204,7 +1576,7 @@ static void store_in_ref_table (struct die_info *, static int is_ref_attr (struct attribute *); -static unsigned int dwarf2_get_ref_die_offset (struct attribute *); +static sect_offset dwarf2_get_ref_die_offset (struct attribute *); static LONGEST dwarf2_get_attr_constant_value (struct attribute *, int); @@ -1222,33 +1594,25 @@ static struct die_info *follow_die_sig (struct die_info *, static struct signatured_type *lookup_signatured_type_at_offset (struct objfile *objfile, - struct dwarf2_section_info *section, - unsigned int offset); + struct dwarf2_section_info *section, sect_offset offset); -static void read_signatured_type_at_offset (struct objfile *objfile, - struct dwarf2_section_info *sect, - unsigned int offset); +static void load_full_type_unit (struct dwarf2_per_cu_data *per_cu); -static void read_signatured_type (struct objfile *, - struct signatured_type *type_sig); +static void read_signatured_type (struct signatured_type *); + +static struct type_unit_group *get_type_unit_group + (struct dwarf2_cu *, struct attribute *); + +static void build_type_unit_groups (die_reader_func_ftype *, void *); /* memory allocation interface */ static struct dwarf_block *dwarf_alloc_block (struct dwarf2_cu *); -static struct abbrev_info *dwarf_alloc_abbrev (struct dwarf2_cu *); - static struct die_info *dwarf_alloc_die (struct dwarf2_cu *, int); -static void initialize_cu_func_list (struct dwarf2_cu *); - -static void add_to_cu_func_list (const char *, CORE_ADDR, CORE_ADDR, - struct dwarf2_cu *); - -static void dwarf_decode_macros (struct line_header *, unsigned int, - char *, bfd *, struct dwarf2_cu *, - struct dwarf2_section_info *, - int); +static void dwarf_decode_macros (struct dwarf2_cu *, unsigned int, + const char *, int); static int attr_form_is_block (struct attribute *); @@ -1264,9 +1628,9 @@ static void dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu); -static gdb_byte *skip_one_die (gdb_byte *buffer, gdb_byte *info_ptr, - struct abbrev_info *abbrev, - struct dwarf2_cu *cu); +static gdb_byte *skip_one_die (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct abbrev_info *abbrev); static void free_stack_comp_unit (void *); @@ -1275,36 +1639,38 @@ static hashval_t partial_die_hash (const void *item); static int partial_die_eq (const void *item_lhs, const void *item_rhs); static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit - (unsigned int offset, struct objfile *objfile); - -static struct dwarf2_per_cu_data *dwarf2_find_comp_unit - (unsigned int offset, struct objfile *objfile); + (sect_offset offset, unsigned int offset_in_dwz, struct objfile *objfile); static void init_one_comp_unit (struct dwarf2_cu *cu, - struct objfile *objfile); + struct dwarf2_per_cu_data *per_cu); static void prepare_one_comp_unit (struct dwarf2_cu *cu, - struct die_info *comp_unit_die); + struct die_info *comp_unit_die, + enum language pretend_language); -static void free_one_comp_unit (void *); +static void free_heap_comp_unit (void *); static void free_cached_comp_units (void *); static void age_cached_comp_units (void); -static void free_one_cached_comp_unit (void *); +static void free_one_cached_comp_unit (struct dwarf2_per_cu_data *); static struct type *set_die_type (struct die_info *, struct type *, struct dwarf2_cu *); static void create_all_comp_units (struct objfile *); -static int create_debug_types_hash_table (struct objfile *objfile); +static int create_all_type_units (struct objfile *); static void load_full_comp_unit (struct dwarf2_per_cu_data *, - struct objfile *); + enum language); + +static void process_full_comp_unit (struct dwarf2_per_cu_data *, + enum language); -static void process_full_comp_unit (struct dwarf2_per_cu_data *); +static void process_full_type_unit (struct dwarf2_per_cu_data *, + enum language); static void dwarf2_add_dependence (struct dwarf2_cu *, struct dwarf2_per_cu_data *); @@ -1313,7 +1679,7 @@ static void dwarf2_mark (struct dwarf2_cu *); static void dwarf2_clear_marks (struct dwarf2_per_cu_data *); -static struct type *get_die_type_at_offset (unsigned int, +static struct type *get_die_type_at_offset (sect_offset, struct dwarf2_per_cu_data *per_cu); static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu); @@ -1321,29 +1687,52 @@ static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu); static void dwarf2_release_queue (void *dummy); static void queue_comp_unit (struct dwarf2_per_cu_data *per_cu, - struct objfile *objfile); + enum language pretend_language); -static void process_queue (struct objfile *objfile); +static int maybe_queue_comp_unit (struct dwarf2_cu *this_cu, + struct dwarf2_per_cu_data *per_cu, + enum language pretend_language); + +static void process_queue (void); static void find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu, - char **name, char **comp_dir); + const char **name, const char **comp_dir); static char *file_full_name (int file, struct line_header *lh, const char *comp_dir); -static gdb_byte *partial_read_comp_unit_head (struct comp_unit_head *header, - gdb_byte *info_ptr, - gdb_byte *buffer, - unsigned int buffer_size, - bfd *abfd, - int is_debug_types_section); +static gdb_byte *read_and_check_comp_unit_head + (struct comp_unit_head *header, + struct dwarf2_section_info *section, + struct dwarf2_section_info *abbrev_section, gdb_byte *info_ptr, + int is_debug_types_section); -static void init_cu_die_reader (struct die_reader_specs *reader, - struct dwarf2_cu *cu); +static void init_cutu_and_read_dies + (struct dwarf2_per_cu_data *this_cu, struct abbrev_table *abbrev_table, + int use_existing_cu, int keep, + die_reader_func_ftype *die_reader_func, void *data); + +static void init_cutu_and_read_dies_simple + (struct dwarf2_per_cu_data *this_cu, + die_reader_func_ftype *die_reader_func, void *data); static htab_t allocate_signatured_type_table (struct objfile *objfile); +static htab_t allocate_dwo_unit_table (struct objfile *objfile); + +static struct dwo_unit *lookup_dwo_comp_unit + (struct dwarf2_per_cu_data *, const char *, const char *, ULONGEST); + +static struct dwo_unit *lookup_dwo_type_unit + (struct signatured_type *, const char *, const char *); + +static void free_dwo_file_cleanup (void *); + +static void process_cu_includes (void); + +static void check_producer (struct dwarf2_cu *cu); + #if WORDS_BIGENDIAN /* Convert VALUE between big- and little-endian. */ @@ -1368,7 +1757,7 @@ byte_swap (offset_type value) /* The suffix for an index file. */ #define INDEX_SUFFIX ".gdb-index" -static const char *dwarf2_physname (char *name, struct die_info *die, +static const char *dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu); /* Try to locate the sections we need for DWARF 2 debugging @@ -1423,13 +1812,17 @@ static void dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) { const struct dwarf2_debug_sections *names; + flagword aflag = bfd_get_section_flags (abfd, sectp); if (vnames == NULL) names = &dwarf2_elf_names; else names = (const struct dwarf2_debug_sections *) vnames; - if (section_is_p (sectp->name, &names->info)) + if ((aflag & SEC_HAS_CONTENTS) == 0) + { + } + else if (section_is_p (sectp->name, &names->info)) { dwarf2_per_objfile->info.asection = sectp; dwarf2_per_objfile->info.size = bfd_get_section_size (sectp); @@ -1464,6 +1857,11 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) dwarf2_per_objfile->str.asection = sectp; dwarf2_per_objfile->str.size = bfd_get_section_size (sectp); } + else if (section_is_p (sectp->name, &names->addr)) + { + dwarf2_per_objfile->addr.asection = sectp; + dwarf2_per_objfile->addr.size = bfd_get_section_size (sectp); + } else if (section_is_p (sectp->name, &names->frame)) { dwarf2_per_objfile->frame.asection = sectp; @@ -1471,13 +1869,8 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) } else if (section_is_p (sectp->name, &names->eh_frame)) { - flagword aflag = bfd_get_section_flags (ignore_abfd, sectp); - - if (aflag & SEC_HAS_CONTENTS) - { - dwarf2_per_objfile->eh_frame.asection = sectp; - dwarf2_per_objfile->eh_frame.size = bfd_get_section_size (sectp); - } + dwarf2_per_objfile->eh_frame.asection = sectp; + dwarf2_per_objfile->eh_frame.size = bfd_get_section_size (sectp); } else if (section_is_p (sectp->name, &names->ranges)) { @@ -1506,86 +1899,8 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) dwarf2_per_objfile->has_section_at_zero = 1; } -/* Decompress a section that was compressed using zlib. Store the - decompressed buffer, and its size, in OUTBUF and OUTSIZE. */ - -static void -zlib_decompress_section (struct objfile *objfile, asection *sectp, - gdb_byte **outbuf, bfd_size_type *outsize) -{ - bfd *abfd = objfile->obfd; -#ifndef HAVE_ZLIB_H - error (_("Support for zlib-compressed DWARF data (from '%s') " - "is disabled in this copy of GDB"), - bfd_get_filename (abfd)); -#else - bfd_size_type compressed_size = bfd_get_section_size (sectp); - gdb_byte *compressed_buffer = xmalloc (compressed_size); - struct cleanup *cleanup = make_cleanup (xfree, compressed_buffer); - bfd_size_type uncompressed_size; - gdb_byte *uncompressed_buffer; - z_stream strm; - int rc; - int header_size = 12; - - if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 - || bfd_bread (compressed_buffer, - compressed_size, abfd) != compressed_size) - error (_("Dwarf Error: Can't read DWARF data from '%s'"), - bfd_get_filename (abfd)); - - /* Read the zlib header. In this case, it should be "ZLIB" followed - by the uncompressed section size, 8 bytes in big-endian order. */ - if (compressed_size < header_size - || strncmp (compressed_buffer, "ZLIB", 4) != 0) - error (_("Dwarf Error: Corrupt DWARF ZLIB header from '%s'"), - bfd_get_filename (abfd)); - uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[11]; - - /* It is possible the section consists of several compressed - buffers concatenated together, so we uncompress in a loop. */ - strm.zalloc = NULL; - strm.zfree = NULL; - strm.opaque = NULL; - 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); - rc = inflateInit (&strm); - while (strm.avail_in > 0) - { - if (rc != Z_OK) - error (_("Dwarf Error: setting up DWARF uncompression in '%s': %d"), - bfd_get_filename (abfd), rc); - strm.next_out = ((Bytef*) uncompressed_buffer - + (uncompressed_size - strm.avail_out)); - rc = inflate (&strm, Z_FINISH); - if (rc != Z_STREAM_END) - error (_("Dwarf Error: zlib error uncompressing from '%s': %d"), - bfd_get_filename (abfd), rc); - rc = inflateReset (&strm); - } - rc = inflateEnd (&strm); - if (rc != Z_OK - || strm.avail_out != 0) - error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"), - bfd_get_filename (abfd), rc); - - do_cleanups (cleanup); - *outbuf = uncompressed_buffer; - *outsize = uncompressed_size; -#endif -} - -/* A helper function that decides whether a section is empty. */ +/* A helper function that decides whether a section is empty, + or not present. */ static int dwarf2_section_empty_p (struct dwarf2_section_info *info) @@ -1593,68 +1908,44 @@ dwarf2_section_empty_p (struct dwarf2_section_info *info) return info->asection == NULL || info->size == 0; } -/* Read the contents of the section SECTP from object file specified by - OBJFILE, store info about the section into INFO. +/* Read the contents of the section INFO. + OBJFILE is the main object file, but not necessarily the file where + the section comes from. E.g., for DWO files INFO->asection->owner + is the bfd of the DWO file. If the section is compressed, uncompress it before returning. */ static void dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) { - bfd *abfd = objfile->obfd; asection *sectp = info->asection; + bfd *abfd; gdb_byte *buf, *retbuf; unsigned char header[4]; if (info->readin) return; info->buffer = NULL; - info->map_addr = NULL; info->readin = 1; if (dwarf2_section_empty_p (info)) return; - /* Check if the file has a 4-byte header indicating compression. */ - if (info->size > sizeof (header) - && bfd_seek (abfd, sectp->filepos, SEEK_SET) == 0 - && bfd_bread (header, sizeof (header), abfd) == sizeof (header)) - { - /* Upon decompression, update the buffer and its size. */ - if (strncmp (header, "ZLIB", sizeof (header)) == 0) - { - zlib_decompress_section (objfile, sectp, &info->buffer, - &info->size); - return; - } - } - -#ifdef HAVE_MMAP - if (pagesize == 0) - pagesize = getpagesize (); + abfd = sectp->owner; - /* Only try to mmap sections which are large enough: we don't want to - waste space due to fragmentation. Also, only try mmap for sections - without relocations. */ - - if (info->size > 4 * pagesize && (sectp->flags & SEC_RELOC) == 0) + /* If the section has relocations, we must read it ourselves. + Otherwise we attach it to the BFD. */ + if ((sectp->flags & SEC_RELOC) == 0) { - info->buffer = bfd_mmap (abfd, 0, info->size, PROT_READ, - MAP_PRIVATE, sectp->filepos, - &info->map_addr, &info->map_len); + const gdb_byte *bytes = gdb_bfd_map_section (sectp, &info->size); - if ((caddr_t)info->buffer != MAP_FAILED) - { -#if HAVE_POSIX_MADVISE - posix_madvise (info->map_addr, info->map_len, POSIX_MADV_WILLNEED); -#endif - return; - } + /* We have to cast away const here for historical reasons. + Fixing dwarf2read to be const-correct would be quite nice. */ + info->buffer = (gdb_byte *) bytes; + return; } -#endif - /* If we get here, we are a normal, not-compressed section. */ - info->buffer = buf - = obstack_alloc (&objfile->objfile_obstack, info->size); + buf = obstack_alloc (&objfile->objfile_obstack, info->size); + info->buffer = buf; /* When debugging .o files, we may need to apply relocations; see http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html . @@ -1730,23 +2021,129 @@ dwarf2_get_section_info (struct objfile *objfile, *sizep = info->size; } - -/* DWARF quick_symbols_functions support. */ +/* A helper function to find the sections for a .dwz file. */ -/* TUs can share .debug_line entries, and there can be a lot more TUs than - unique line tables, so we maintain a separate table of all .debug_line - derived entries to support the sharing. - All the quick functions need is the list of file names. We discard the - line_header when we're done and don't need to record it here. */ -struct quick_file_names +static void +locate_dwz_sections (bfd *abfd, asection *sectp, void *arg) { - /* The offset in .debug_line of the line table. We hash on this. */ - unsigned int offset; + struct dwz_file *dwz_file = arg; - /* The number of entries in file_names, real_names. */ - unsigned int num_file_names; + /* Note that we only support the standard ELF names, because .dwz + is ELF-only (at the time of writing). */ + if (section_is_p (sectp->name, &dwarf2_elf_names.abbrev)) + { + dwz_file->abbrev.asection = sectp; + dwz_file->abbrev.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.info)) + { + dwz_file->info.asection = sectp; + dwz_file->info.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.str)) + { + dwz_file->str.asection = sectp; + dwz_file->str.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.line)) + { + dwz_file->line.asection = sectp; + dwz_file->line.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.macro)) + { + dwz_file->macro.asection = sectp; + dwz_file->macro.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.gdb_index)) + { + dwz_file->gdb_index.asection = sectp; + dwz_file->gdb_index.size = bfd_get_section_size (sectp); + } +} - /* The file names from the line table, after being run through +/* Open the separate '.dwz' debug file, if needed. Error if the file + cannot be found. */ + +static struct dwz_file * +dwarf2_get_dwz_file (void) +{ + bfd *abfd, *dwz_bfd; + asection *section; + gdb_byte *data; + struct cleanup *cleanup; + const char *filename; + struct dwz_file *result; + + if (dwarf2_per_objfile->dwz_file != NULL) + return dwarf2_per_objfile->dwz_file; + + abfd = dwarf2_per_objfile->objfile->obfd; + section = bfd_get_section_by_name (abfd, ".gnu_debugaltlink"); + if (section == NULL) + error (_("could not find '.gnu_debugaltlink' section")); + if (!bfd_malloc_and_get_section (abfd, section, &data)) + error (_("could not read '.gnu_debugaltlink' section: %s"), + bfd_errmsg (bfd_get_error ())); + cleanup = make_cleanup (xfree, data); + + filename = data; + if (!IS_ABSOLUTE_PATH (filename)) + { + char *abs = gdb_realpath (dwarf2_per_objfile->objfile->name); + char *rel; + + make_cleanup (xfree, abs); + abs = ldirname (abs); + make_cleanup (xfree, abs); + + rel = concat (abs, SLASH_STRING, filename, (char *) NULL); + make_cleanup (xfree, rel); + filename = rel; + } + + /* The format is just a NUL-terminated file name, followed by the + build-id. For now, though, we ignore the build-id. */ + dwz_bfd = gdb_bfd_open (filename, gnutarget, -1); + if (dwz_bfd == NULL) + error (_("could not read '%s': %s"), filename, + bfd_errmsg (bfd_get_error ())); + + if (!bfd_check_format (dwz_bfd, bfd_object)) + { + gdb_bfd_unref (dwz_bfd); + error (_("file '%s' was not usable: %s"), filename, + bfd_errmsg (bfd_get_error ())); + } + + result = OBSTACK_ZALLOC (&dwarf2_per_objfile->objfile->objfile_obstack, + struct dwz_file); + result->dwz_bfd = dwz_bfd; + + bfd_map_over_sections (dwz_bfd, locate_dwz_sections, result); + + do_cleanups (cleanup); + + dwarf2_per_objfile->dwz_file = result; + return result; +} + +/* DWARF quick_symbols_functions support. */ + +/* TUs can share .debug_line entries, and there can be a lot more TUs than + unique line tables, so we maintain a separate table of all .debug_line + derived entries to support the sharing. + All the quick functions need is the list of file names. We discard the + line_header when we're done and don't need to record it here. */ +struct quick_file_names +{ + /* The data used to construct the hash key. */ + struct stmt_list_hash hash; + + /* The number of entries in file_names, real_names. */ + unsigned int num_file_names; + + /* The file names from the line table, after being run through file_full_name. */ const char **file_names; @@ -1778,6 +2175,34 @@ struct dwarf2_per_cu_quick_data unsigned int no_file_data : 1; }; +/* Utility hash function for a stmt_list_hash. */ + +static hashval_t +hash_stmt_list_entry (const struct stmt_list_hash *stmt_list_hash) +{ + hashval_t v = 0; + + if (stmt_list_hash->dwo_unit != NULL) + v += (uintptr_t) stmt_list_hash->dwo_unit->dwo_file; + v += stmt_list_hash->line_offset.sect_off; + return v; +} + +/* Utility equality function for a stmt_list_hash. */ + +static int +eq_stmt_list_entry (const struct stmt_list_hash *lhs, + const struct stmt_list_hash *rhs) +{ + if ((lhs->dwo_unit != NULL) != (rhs->dwo_unit != NULL)) + return 0; + if (lhs->dwo_unit != NULL + && lhs->dwo_unit->dwo_file != rhs->dwo_unit->dwo_file) + return 0; + + return lhs->line_offset.sect_off == rhs->line_offset.sect_off; +} + /* Hash function for a quick_file_names. */ static hashval_t @@ -1785,7 +2210,7 @@ hash_file_name_entry (const void *e) { const struct quick_file_names *file_data = e; - return file_data->offset; + return hash_stmt_list_entry (&file_data->hash); } /* Equality function for a quick_file_names. */ @@ -1796,7 +2221,7 @@ eq_file_name_entry (const void *a, const void *b) const struct quick_file_names *ea = a; const struct quick_file_names *eb = b; - return ea->offset == eb->offset; + return eq_stmt_list_entry (&ea->hash, &eb->hash); } /* Delete function for a quick_file_names. */ @@ -1835,34 +2260,39 @@ create_quick_file_names_table (unsigned int nr_initial_entries) static void load_cu (struct dwarf2_per_cu_data *per_cu) { - if (per_cu->debug_types_section) - read_signatured_type_at_offset (per_cu->objfile, - per_cu->debug_types_section, - per_cu->offset); + if (per_cu->is_debug_types) + load_full_type_unit (per_cu); else - load_full_comp_unit (per_cu, per_cu->objfile); - - dwarf2_find_base_address (per_cu->cu->dies, per_cu->cu); + load_full_comp_unit (per_cu, language_minimal); gdb_assert (per_cu->cu != NULL); + + dwarf2_find_base_address (per_cu->cu->dies, per_cu->cu); } -/* Read in the symbols for PER_CU. OBJFILE is the objfile from which - this CU came. */ +/* Read in the symbols for PER_CU. */ static void -dw2_do_instantiate_symtab (struct objfile *objfile, - struct dwarf2_per_cu_data *per_cu) +dw2_do_instantiate_symtab (struct dwarf2_per_cu_data *per_cu) { struct cleanup *back_to; - back_to = make_cleanup (dwarf2_release_queue, NULL); + /* Skip type_unit_groups, reading the type units they contain + is handled elsewhere. */ + if (IS_TYPE_UNIT_GROUP (per_cu)) + return; - queue_comp_unit (per_cu, objfile); + back_to = make_cleanup (dwarf2_release_queue, NULL); - load_cu (per_cu); + if (dwarf2_per_objfile->using_index + ? per_cu->v.quick->symtab == NULL + : (per_cu->v.psymtab == NULL || !per_cu->v.psymtab->readin)) + { + queue_comp_unit (per_cu, language_minimal); + load_cu (per_cu); + } - process_queue (objfile); + process_queue (); /* Age the cache, releasing compilation units that have not been used recently. */ @@ -1876,20 +2306,32 @@ dw2_do_instantiate_symtab (struct objfile *objfile, table. */ static struct symtab * -dw2_instantiate_symtab (struct objfile *objfile, - struct dwarf2_per_cu_data *per_cu) +dw2_instantiate_symtab (struct dwarf2_per_cu_data *per_cu) { + gdb_assert (dwarf2_per_objfile->using_index); if (!per_cu->v.quick->symtab) { struct cleanup *back_to = make_cleanup (free_cached_comp_units, NULL); increment_reading_symtab (); - dw2_do_instantiate_symtab (objfile, per_cu); + dw2_do_instantiate_symtab (per_cu); + process_cu_includes (); do_cleanups (back_to); } return per_cu->v.quick->symtab; } -/* Return the CU given its index. */ +/* Return the CU given its index. + + This is intended for loops like: + + for (i = 0; i < (dwarf2_per_objfile->n_comp_units + + dwarf2_per_objfile->n_type_units); ++i) + { + struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); + + ...; + } +*/ static struct dwarf2_per_cu_data * dw2_get_cu (int index) @@ -1897,76 +2339,106 @@ dw2_get_cu (int index) if (index >= dwarf2_per_objfile->n_comp_units) { index -= dwarf2_per_objfile->n_comp_units; - return dwarf2_per_objfile->type_comp_units[index]; + gdb_assert (index < dwarf2_per_objfile->n_type_units); + return &dwarf2_per_objfile->all_type_units[index]->per_cu; } + return dwarf2_per_objfile->all_comp_units[index]; } -/* A helper function that knows how to read a 64-bit value in a way - that doesn't make gdb die. Returns 1 if the conversion went ok, 0 - otherwise. */ +/* Return the primary CU given its index. + The difference between this function and dw2_get_cu is in the handling + of type units (TUs). Here we return the type_unit_group object. -static int -extract_cu_value (const char *bytes, ULONGEST *result) -{ - if (sizeof (ULONGEST) < 8) - { - int i; + This is intended for loops like: - /* Ignore the upper 4 bytes if they are all zero. */ - for (i = 0; i < 4; ++i) - if (bytes[i + 4] != 0) - return 0; + for (i = 0; i < (dwarf2_per_objfile->n_comp_units + + dwarf2_per_objfile->n_type_unit_groups); ++i) + { + struct dwarf2_per_cu_data *per_cu = dw2_get_primary_cu (i); + + ...; + } +*/ - *result = extract_unsigned_integer (bytes, 4, BFD_ENDIAN_LITTLE); +static struct dwarf2_per_cu_data * +dw2_get_primary_cu (int index) +{ + if (index >= dwarf2_per_objfile->n_comp_units) + { + index -= dwarf2_per_objfile->n_comp_units; + gdb_assert (index < dwarf2_per_objfile->n_type_unit_groups); + return &dwarf2_per_objfile->all_type_unit_groups[index]->per_cu; } - else - *result = extract_unsigned_integer (bytes, 8, BFD_ENDIAN_LITTLE); - return 1; + + return dwarf2_per_objfile->all_comp_units[index]; } -/* Read the CU list from the mapped index, and use it to create all - the CU objects for this objfile. Return 0 if something went wrong, - 1 if everything went ok. */ +/* A helper for create_cus_from_index that handles a given list of + CUs. */ -static int -create_cus_from_index (struct objfile *objfile, const gdb_byte *cu_list, - offset_type cu_list_elements) +static void +create_cus_from_index_list (struct objfile *objfile, + const gdb_byte *cu_list, offset_type n_elements, + struct dwarf2_section_info *section, + int is_dwz, + int base_offset) { offset_type i; - dwarf2_per_objfile->n_comp_units = cu_list_elements / 2; - dwarf2_per_objfile->all_comp_units - = obstack_alloc (&objfile->objfile_obstack, - dwarf2_per_objfile->n_comp_units - * sizeof (struct dwarf2_per_cu_data *)); - - for (i = 0; i < cu_list_elements; i += 2) + for (i = 0; i < n_elements; i += 2) { struct dwarf2_per_cu_data *the_cu; ULONGEST offset, length; - if (!extract_cu_value (cu_list, &offset) - || !extract_cu_value (cu_list + 8, &length)) - return 0; + gdb_static_assert (sizeof (ULONGEST) >= 8); + offset = extract_unsigned_integer (cu_list, 8, BFD_ENDIAN_LITTLE); + length = extract_unsigned_integer (cu_list + 8, 8, BFD_ENDIAN_LITTLE); cu_list += 2 * 8; the_cu = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwarf2_per_cu_data); - the_cu->offset = offset; + the_cu->offset.sect_off = offset; the_cu->length = length; the_cu->objfile = objfile; + the_cu->info_or_types_section = section; the_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwarf2_per_cu_quick_data); - dwarf2_per_objfile->all_comp_units[i / 2] = the_cu; + the_cu->is_dwz = is_dwz; + dwarf2_per_objfile->all_comp_units[base_offset + i / 2] = the_cu; } +} - return 1; +/* Read the CU list from the mapped index, and use it to create all + the CU objects for this objfile. */ + +static void +create_cus_from_index (struct objfile *objfile, + const gdb_byte *cu_list, offset_type cu_list_elements, + const gdb_byte *dwz_list, offset_type dwz_elements) +{ + struct dwz_file *dwz; + + dwarf2_per_objfile->n_comp_units = (cu_list_elements + dwz_elements) / 2; + dwarf2_per_objfile->all_comp_units + = obstack_alloc (&objfile->objfile_obstack, + dwarf2_per_objfile->n_comp_units + * sizeof (struct dwarf2_per_cu_data *)); + + create_cus_from_index_list (objfile, cu_list, cu_list_elements, + &dwarf2_per_objfile->info, 0, 0); + + if (dwz_elements == 0) + return; + + dwz = dwarf2_get_dwz_file (); + create_cus_from_index_list (objfile, dwz_list, dwz_elements, &dwz->info, 1, + cu_list_elements / 2); } /* Create the signatured type hash table from the index. */ -static int +static void create_signatured_type_table_from_index (struct objfile *objfile, struct dwarf2_section_info *section, const gdb_byte *bytes, @@ -1975,46 +2447,46 @@ create_signatured_type_table_from_index (struct objfile *objfile, offset_type i; htab_t sig_types_hash; - dwarf2_per_objfile->n_type_comp_units = elements / 3; - dwarf2_per_objfile->type_comp_units + dwarf2_per_objfile->n_type_units = elements / 3; + dwarf2_per_objfile->all_type_units = obstack_alloc (&objfile->objfile_obstack, - dwarf2_per_objfile->n_type_comp_units - * sizeof (struct dwarf2_per_cu_data *)); + dwarf2_per_objfile->n_type_units + * sizeof (struct signatured_type *)); sig_types_hash = allocate_signatured_type_table (objfile); for (i = 0; i < elements; i += 3) { - struct signatured_type *type_sig; - ULONGEST offset, type_offset, signature; + struct signatured_type *sig_type; + ULONGEST offset, type_offset_in_tu, signature; void **slot; - if (!extract_cu_value (bytes, &offset) - || !extract_cu_value (bytes + 8, &type_offset)) - return 0; + gdb_static_assert (sizeof (ULONGEST) >= 8); + offset = extract_unsigned_integer (bytes, 8, BFD_ENDIAN_LITTLE); + type_offset_in_tu = extract_unsigned_integer (bytes + 8, 8, + BFD_ENDIAN_LITTLE); signature = extract_unsigned_integer (bytes + 16, 8, BFD_ENDIAN_LITTLE); bytes += 3 * 8; - type_sig = OBSTACK_ZALLOC (&objfile->objfile_obstack, + sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct signatured_type); - type_sig->signature = signature; - type_sig->type_offset = type_offset; - type_sig->per_cu.debug_types_section = section; - type_sig->per_cu.offset = offset; - type_sig->per_cu.objfile = objfile; - type_sig->per_cu.v.quick + sig_type->signature = signature; + sig_type->type_offset_in_tu.cu_off = type_offset_in_tu; + sig_type->per_cu.is_debug_types = 1; + sig_type->per_cu.info_or_types_section = section; + sig_type->per_cu.offset.sect_off = offset; + sig_type->per_cu.objfile = objfile; + sig_type->per_cu.v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwarf2_per_cu_quick_data); - slot = htab_find_slot (sig_types_hash, type_sig, INSERT); - *slot = type_sig; + slot = htab_find_slot (sig_types_hash, sig_type, INSERT); + *slot = sig_type; - dwarf2_per_objfile->type_comp_units[i / 3] = &type_sig->per_cu; + dwarf2_per_objfile->all_type_units[i / 3] = sig_type; } dwarf2_per_objfile->signatured_types = sig_types_hash; - - return 1; } /* Read the address map data from the mapped index, and use it to @@ -2117,7 +2589,7 @@ find_slot_in_mapped_hash (struct mapped_index *index, const char *name, } /* Index version 4 did not support case insensitive searches. But the - indexes for case insensitive languages are built in lowercase, therefore + indices for case insensitive languages are built in lowercase, therefore simulate our NAME being searched is also lowercased. */ hash = mapped_index_string_hash ((index->version == 4 && case_sensitivity == case_sensitive_off @@ -2152,63 +2624,108 @@ find_slot_in_mapped_hash (struct mapped_index *index, const char *name, } } -/* Read the index file. If everything went ok, initialize the "quick" - elements of all the CUs and return 1. Otherwise, return 0. */ +/* A helper function that reads the .gdb_index from SECTION and fills + in MAP. FILENAME is the name of the file containing the section; + it is used for error reporting. DEPRECATED_OK is nonzero if it is + ok to use deprecated sections. + + CU_LIST, CU_LIST_ELEMENTS, TYPES_LIST, and TYPES_LIST_ELEMENTS are + out parameters that are filled in with information about the CU and + TU lists in the section. + + Returns 1 if all went well, 0 otherwise. */ static int -dwarf2_read_index (struct objfile *objfile) +read_index_from_section (struct objfile *objfile, + const char *filename, + int deprecated_ok, + struct dwarf2_section_info *section, + struct mapped_index *map, + const gdb_byte **cu_list, + offset_type *cu_list_elements, + const gdb_byte **types_list, + offset_type *types_list_elements) { char *addr; - struct mapped_index *map; + offset_type version; offset_type *metadata; - const gdb_byte *cu_list; - const gdb_byte *types_list = NULL; - offset_type version, cu_list_elements; - offset_type types_list_elements = 0; int i; - if (dwarf2_section_empty_p (&dwarf2_per_objfile->gdb_index)) + if (dwarf2_section_empty_p (section)) return 0; /* Older elfutils strip versions could keep the section in the main executable while splitting it for the separate debug info file. */ - if ((bfd_get_file_flags (dwarf2_per_objfile->gdb_index.asection) - & SEC_HAS_CONTENTS) == 0) + if ((bfd_get_file_flags (section->asection) & SEC_HAS_CONTENTS) == 0) return 0; - dwarf2_read_section (objfile, &dwarf2_per_objfile->gdb_index); + dwarf2_read_section (objfile, section); - addr = dwarf2_per_objfile->gdb_index.buffer; + addr = section->buffer; /* Version check. */ version = MAYBE_SWAP (*(offset_type *) addr); /* Versions earlier than 3 emitted every copy of a psymbol. This causes the index to behave very poorly for certain requests. Version 3 contained incomplete addrmap. So, it seems better to just ignore such - indices. Index version 4 uses a different hash function than index - version 5 and later. */ + indices. */ if (version < 4) - return 0; + { + static int warning_printed = 0; + if (!warning_printed) + { + warning (_("Skipping obsolete .gdb_index section in %s."), + filename); + warning_printed = 1; + } + return 0; + } + /* Index version 4 uses a different hash function than index version + 5 and later. + + Versions earlier than 6 did not emit psymbols for inlined + functions. Using these files will cause GDB not to be able to + set breakpoints on inlined functions by name, so we ignore these + indices unless the user has done + "set use-deprecated-index-sections on". */ + if (version < 6 && !deprecated_ok) + { + static int warning_printed = 0; + if (!warning_printed) + { + warning (_("\ +Skipping deprecated .gdb_index section in %s.\n\ +Do \"set use-deprecated-index-sections on\" before the file is read\n\ +to use the section anyway."), + filename); + warning_printed = 1; + } + return 0; + } + /* Version 7 indices generated by gold refer to the CU for a symbol instead + of the TU (for symbols coming from TUs). It's just a performance bug, and + we can't distinguish gdb-generated indices from gold-generated ones, so + nothing to do here. */ + /* Indexes with higher version than the one supported by GDB may be no longer backward compatible. */ - if (version > 5) + if (version > 8) return 0; - map = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct mapped_index); map->version = version; - map->total_size = dwarf2_per_objfile->gdb_index.size; + map->total_size = section->size; metadata = (offset_type *) (addr + sizeof (offset_type)); i = 0; - cu_list = addr + MAYBE_SWAP (metadata[i]); - cu_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - MAYBE_SWAP (metadata[i])) - / 8); + *cu_list = addr + MAYBE_SWAP (metadata[i]); + *cu_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - MAYBE_SWAP (metadata[i])) + / 8); ++i; - types_list = addr + MAYBE_SWAP (metadata[i]); - types_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - - MAYBE_SWAP (metadata[i])) - / 8); + *types_list = addr + MAYBE_SWAP (metadata[i]); + *types_list_elements = ((MAYBE_SWAP (metadata[i + 1]) + - MAYBE_SWAP (metadata[i])) + / 8); ++i; map->address_table = addr + MAYBE_SWAP (metadata[i]); @@ -2224,9 +2741,56 @@ dwarf2_read_index (struct objfile *objfile) map->constant_pool = addr + MAYBE_SWAP (metadata[i]); - if (!create_cus_from_index (objfile, cu_list, cu_list_elements)) + return 1; +} + + +/* Read the index file. If everything went ok, initialize the "quick" + elements of all the CUs and return 1. Otherwise, return 0. */ + +static int +dwarf2_read_index (struct objfile *objfile) +{ + struct mapped_index local_map, *map; + const gdb_byte *cu_list, *types_list, *dwz_list = NULL; + offset_type cu_list_elements, types_list_elements, dwz_list_elements = 0; + + if (!read_index_from_section (objfile, objfile->name, + use_deprecated_index_sections, + &dwarf2_per_objfile->gdb_index, &local_map, + &cu_list, &cu_list_elements, + &types_list, &types_list_elements)) + return 0; + + /* Don't use the index if it's empty. */ + if (local_map.symbol_table_slots == 0) return 0; + /* If there is a .dwz file, read it so we can get its CU list as + well. */ + if (bfd_get_section_by_name (objfile->obfd, ".gnu_debugaltlink") != NULL) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + struct mapped_index dwz_map; + const gdb_byte *dwz_types_ignore; + offset_type dwz_types_elements_ignore; + + if (!read_index_from_section (objfile, bfd_get_filename (dwz->dwz_bfd), + 1, + &dwz->gdb_index, &dwz_map, + &dwz_list, &dwz_list_elements, + &dwz_types_ignore, + &dwz_types_elements_ignore)) + { + warning (_("could not read '.gdb_index' section from %s; skipping"), + bfd_get_filename (dwz->dwz_bfd)); + return 0; + } + } + + create_cus_from_index (objfile, cu_list, cu_list_elements, dwz_list, + dwz_list_elements); + if (types_list_elements) { struct dwarf2_section_info *section; @@ -2239,13 +2803,14 @@ dwarf2_read_index (struct objfile *objfile) section = VEC_index (dwarf2_section_info_def, dwarf2_per_objfile->types, 0); - if (!create_signatured_type_table_from_index (objfile, section, - types_list, - types_list_elements)) - return 0; + create_signatured_type_table_from_index (objfile, section, types_list, + types_list_elements); } - create_addrmap_from_index (objfile, map); + create_addrmap_from_index (objfile, &local_map); + + map = obstack_alloc (&objfile->objfile_obstack, sizeof (struct mapped_index)); + *map = local_map; dwarf2_per_objfile->index_table = map; dwarf2_per_objfile->using_index = 1; @@ -2265,74 +2830,52 @@ dw2_setup (struct objfile *objfile) gdb_assert (dwarf2_per_objfile); } -/* A helper for the "quick" functions which attempts to read the line - table for THIS_CU. */ +/* die_reader_func for dw2_get_file_names. */ -static struct quick_file_names * -dw2_get_file_names (struct objfile *objfile, - struct dwarf2_per_cu_data *this_cu) +static void +dw2_get_file_names_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data) { - bfd *abfd = objfile->obfd; + struct dwarf2_cu *cu = reader->cu; + struct dwarf2_per_cu_data *this_cu = cu->per_cu; + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_per_cu_data *lh_cu; struct line_header *lh; struct attribute *attr; - struct cleanup *cleanups; - struct die_info *comp_unit_die; - struct dwarf2_section_info* sec; - gdb_byte *info_ptr, *buffer; - int has_children, i; - struct dwarf2_cu cu; - unsigned int bytes_read, buffer_size; - struct die_reader_specs reader_specs; - char *name, *comp_dir; + int i; + const char *name, *comp_dir; void **slot; struct quick_file_names *qfn; unsigned int line_offset; - if (this_cu->v.quick->file_names != NULL) - return this_cu->v.quick->file_names; - /* If we know there is no line data, no point in looking again. */ - if (this_cu->v.quick->no_file_data) - return NULL; - - init_one_comp_unit (&cu, objfile); - cleanups = make_cleanup (free_stack_comp_unit, &cu); - - if (this_cu->debug_types_section) - sec = this_cu->debug_types_section; - else - sec = &dwarf2_per_objfile->info; - dwarf2_read_section (objfile, sec); - buffer_size = sec->size; - buffer = sec->buffer; - info_ptr = buffer + this_cu->offset; - - info_ptr = partial_read_comp_unit_head (&cu.header, info_ptr, - buffer, buffer_size, - abfd, - this_cu->debug_types_section != NULL); - - /* Skip dummy compilation units. */ - if (info_ptr >= buffer + buffer_size - || peek_abbrev_code (abfd, info_ptr) == 0) + /* Our callers never want to match partial units -- instead they + will match the enclosing full CU. */ + if (comp_unit_die->tag == DW_TAG_partial_unit) { - do_cleanups (cleanups); - return NULL; + this_cu->v.quick->no_file_data = 1; + return; } - this_cu->cu = &cu; - cu.per_cu = this_cu; - - dwarf2_read_abbrevs (abfd, &cu); - make_cleanup (dwarf2_free_abbrev_table, &cu); + /* If we're reading the line header for TUs, store it in the "per_cu" + for tu_group. */ + if (this_cu->is_debug_types) + { + struct type_unit_group *tu_group = data; - init_cu_die_reader (&reader_specs, &cu); - read_full_die (&reader_specs, &comp_unit_die, info_ptr, - &has_children); + gdb_assert (tu_group != NULL); + lh_cu = &tu_group->per_cu; + } + else + lh_cu = this_cu; lh = NULL; slot = NULL; line_offset = 0; - attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, &cu); + + attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu); if (attr) { struct quick_file_names find_entry; @@ -2341,31 +2884,31 @@ dw2_get_file_names (struct objfile *objfile, /* We may have already read in this line header (TU line header sharing). If we have we're done. */ - find_entry.offset = line_offset; + find_entry.hash.dwo_unit = cu->dwo_unit; + find_entry.hash.line_offset.sect_off = line_offset; slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table, &find_entry, INSERT); if (*slot != NULL) { - do_cleanups (cleanups); - this_cu->v.quick->file_names = *slot; - return *slot; + lh_cu->v.quick->file_names = *slot; + return; } - lh = dwarf_decode_line_header (line_offset, abfd, &cu); + lh = dwarf_decode_line_header (line_offset, cu); } if (lh == NULL) { - do_cleanups (cleanups); - this_cu->v.quick->no_file_data = 1; - return NULL; + lh_cu->v.quick->no_file_data = 1; + return; } qfn = obstack_alloc (&objfile->objfile_obstack, sizeof (*qfn)); - qfn->offset = line_offset; + qfn->hash.dwo_unit = cu->dwo_unit; + qfn->hash.line_offset.sect_off = line_offset; gdb_assert (slot != NULL); *slot = qfn; - find_file_and_directory (comp_unit_die, &cu, &name, &comp_dir); + find_file_and_directory (comp_unit_die, cu, &name, &comp_dir); qfn->num_file_names = lh->num_file_names; qfn->file_names = obstack_alloc (&objfile->objfile_obstack, @@ -2375,10 +2918,44 @@ dw2_get_file_names (struct objfile *objfile, qfn->real_names = NULL; free_line_header (lh); - do_cleanups (cleanups); - this_cu->v.quick->file_names = qfn; - return qfn; + lh_cu->v.quick->file_names = qfn; +} + +/* A helper for the "quick" functions which attempts to read the line + table for THIS_CU. */ + +static struct quick_file_names * +dw2_get_file_names (struct objfile *objfile, + struct dwarf2_per_cu_data *this_cu) +{ + /* For TUs this should only be called on the parent group. */ + if (this_cu->is_debug_types) + gdb_assert (IS_TYPE_UNIT_GROUP (this_cu)); + + if (this_cu->v.quick->file_names != NULL) + return this_cu->v.quick->file_names; + /* If we know there is no line data, no point in looking again. */ + if (this_cu->v.quick->no_file_data) + return NULL; + + /* If DWO files are in use, we can still find the DW_AT_stmt_list attribute + in the stub for CUs, there's is no need to lookup the DWO file. + However, that's not the case for TUs where DW_AT_stmt_list lives in the + DWO file. */ + if (this_cu->is_debug_types) + { + struct type_unit_group *tu_group = this_cu->type_unit_group; + + init_cutu_and_read_dies (tu_group->t.first_tu, NULL, 0, 0, + dw2_get_file_names_reader, tu_group); + } + else + init_cutu_and_read_dies_simple (this_cu, dw2_get_file_names_reader, NULL); + + if (this_cu->v.quick->no_file_data) + return NULL; + return this_cu->v.quick->file_names; } /* A helper for the "quick" functions which computes and caches the @@ -2405,7 +2982,7 @@ dw2_find_last_source_symtab (struct objfile *objfile) dw2_setup (objfile); index = dwarf2_per_objfile->n_comp_units - 1; - return dw2_instantiate_symtab (objfile, dw2_get_cu (index)); + return dw2_instantiate_symtab (dw2_get_cu (index)); } /* Traversal function for dw2_forget_cached_source_info. */ @@ -2444,8 +3021,7 @@ dw2_forget_cached_source_info (struct objfile *objfile) static int dw2_map_expand_apply (struct objfile *objfile, struct dwarf2_per_cu_data *per_cu, - const char *name, - const char *full_path, const char *real_path, + const char *name, const char *real_path, int (*callback) (struct symtab *, void *), void *data) { @@ -2457,9 +3033,9 @@ dw2_map_expand_apply (struct objfile *objfile, /* This may expand more than one symtab, and we want to iterate over all of them. */ - dw2_instantiate_symtab (objfile, per_cu); + dw2_instantiate_symtab (per_cu); - return iterate_over_some_symtabs (name, full_path, real_path, callback, data, + return iterate_over_some_symtabs (name, real_path, callback, data, objfile->symtabs, last_made); } @@ -2467,22 +3043,22 @@ dw2_map_expand_apply (struct objfile *objfile, static int dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name, - const char *full_path, const char *real_path, + const char *real_path, int (*callback) (struct symtab *, void *), void *data) { int i; const char *name_basename = lbasename (name); - int check_basename = name_basename == name; - struct dwarf2_per_cu_data *base_cu = NULL; dw2_setup (objfile); - for (i = 0; i < (dwarf2_per_objfile->n_comp_units - + dwarf2_per_objfile->n_type_comp_units); ++i) + /* The rule is CUs specify all the files, including those used by + any TU, so there's no need to scan TUs here. */ + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) { int j; - struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); + struct dwarf2_per_cu_data *per_cu = dw2_get_primary_cu (i); struct quick_file_names *file_data; /* We only need to look at symtabs not already expanded. */ @@ -2496,50 +3072,37 @@ dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name, for (j = 0; j < file_data->num_file_names; ++j) { const char *this_name = file_data->file_names[j]; + const char *this_real_name; - if (FILENAME_CMP (name, this_name) == 0) + if (compare_filenames_for_search (this_name, name)) { - if (dw2_map_expand_apply (objfile, per_cu, - name, full_path, real_path, + if (dw2_map_expand_apply (objfile, per_cu, name, real_path, callback, data)) return 1; } - if (check_basename && ! base_cu - && FILENAME_CMP (lbasename (this_name), name) == 0) - base_cu = per_cu; - /* Before we invoke realpath, which can get expensive when many files are involved, do a quick comparison of the basenames. */ if (! basenames_may_differ && FILENAME_CMP (lbasename (this_name), name_basename) != 0) continue; - if (full_path != NULL) + this_real_name = dw2_get_real_path (objfile, file_data, j); + if (compare_filenames_for_search (this_real_name, name)) { - const char *this_real_name = dw2_get_real_path (objfile, - file_data, j); - - if (this_real_name != NULL - && FILENAME_CMP (full_path, this_real_name) == 0) - { - if (dw2_map_expand_apply (objfile, per_cu, - name, full_path, real_path, - callback, data)) - return 1; - } + if (dw2_map_expand_apply (objfile, per_cu, name, real_path, + callback, data)) + return 1; } if (real_path != NULL) { - const char *this_real_name = dw2_get_real_path (objfile, - file_data, j); - + gdb_assert (IS_ABSOLUTE_PATH (real_path)); + gdb_assert (IS_ABSOLUTE_PATH (name)); if (this_real_name != NULL && FILENAME_CMP (real_path, this_real_name) == 0) { - if (dw2_map_expand_apply (objfile, per_cu, - name, full_path, real_path, + if (dw2_map_expand_apply (objfile, per_cu, name, real_path, callback, data)) return 1; } @@ -2547,60 +3110,171 @@ dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name, } } - if (base_cu) - { - if (dw2_map_expand_apply (objfile, base_cu, - name, full_path, real_path, - callback, data)) - return 1; - } - return 0; } -static struct symtab * -dw2_lookup_symbol (struct objfile *objfile, int block_index, - const char *name, domain_enum domain) +/* Struct used to manage iterating over all CUs looking for a symbol. */ + +struct dw2_symtab_iterator { - /* We do all the work in the pre_expand_symtabs_matching hook - instead. */ - return NULL; -} + /* The internalized form of .gdb_index. */ + struct mapped_index *index; + /* If non-zero, only look for symbols that match BLOCK_INDEX. */ + int want_specific_block; + /* One of GLOBAL_BLOCK or STATIC_BLOCK. + Unused if !WANT_SPECIFIC_BLOCK. */ + int block_index; + /* The kind of symbol we're looking for. */ + domain_enum domain; + /* The list of CUs from the index entry of the symbol, + or NULL if not found. */ + offset_type *vec; + /* The next element in VEC to look at. */ + int next; + /* The number of elements in VEC, or zero if there is no match. */ + int length; +}; -/* A helper function that expands all symtabs that hold an object - named NAME. */ +/* Initialize the index symtab iterator ITER. + If WANT_SPECIFIC_BLOCK is non-zero, only look for symbols + in block BLOCK_INDEX. Otherwise BLOCK_INDEX is ignored. */ static void -dw2_do_expand_symtabs_matching (struct objfile *objfile, const char *name) -{ - dw2_setup (objfile); - - /* index_table is NULL if OBJF_READNOW. */ - if (dwarf2_per_objfile->index_table) +dw2_symtab_iter_init (struct dw2_symtab_iterator *iter, + struct mapped_index *index, + int want_specific_block, + int block_index, + domain_enum domain, + const char *name) +{ + iter->index = index; + iter->want_specific_block = want_specific_block; + iter->block_index = block_index; + iter->domain = domain; + iter->next = 0; + + if (find_slot_in_mapped_hash (index, name, &iter->vec)) + iter->length = MAYBE_SWAP (*iter->vec); + else { - offset_type *vec; + iter->vec = NULL; + iter->length = 0; + } +} - if (find_slot_in_mapped_hash (dwarf2_per_objfile->index_table, - name, &vec)) +/* Return the next matching CU or NULL if there are no more. */ + +static struct dwarf2_per_cu_data * +dw2_symtab_iter_next (struct dw2_symtab_iterator *iter) +{ + for ( ; iter->next < iter->length; ++iter->next) + { + offset_type cu_index_and_attrs = + MAYBE_SWAP (iter->vec[iter->next + 1]); + offset_type cu_index = GDB_INDEX_CU_VALUE (cu_index_and_attrs); + struct dwarf2_per_cu_data *per_cu = dw2_get_cu (cu_index); + int want_static = iter->block_index != GLOBAL_BLOCK; + /* This value is only valid for index versions >= 7. */ + int is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (cu_index_and_attrs); + gdb_index_symbol_kind symbol_kind = + GDB_INDEX_SYMBOL_KIND_VALUE (cu_index_and_attrs); + /* Only check the symbol attributes if they're present. + Indices prior to version 7 don't record them, + and indices >= 7 may elide them for certain symbols + (gold does this). */ + int attrs_valid = + (iter->index->version >= 7 + && symbol_kind != GDB_INDEX_SYMBOL_KIND_NONE); + + /* Skip if already read in. */ + if (per_cu->v.quick->symtab) + continue; + + if (attrs_valid + && iter->want_specific_block + && want_static != is_static) + continue; + + /* Only check the symbol's kind if it has one. */ + if (attrs_valid) { - offset_type i, len = MAYBE_SWAP (*vec); - for (i = 0; i < len; ++i) + switch (iter->domain) { - offset_type cu_index = MAYBE_SWAP (vec[i + 1]); - struct dwarf2_per_cu_data *per_cu = dw2_get_cu (cu_index); - - dw2_instantiate_symtab (objfile, per_cu); + case VAR_DOMAIN: + if (symbol_kind != GDB_INDEX_SYMBOL_KIND_VARIABLE + && symbol_kind != GDB_INDEX_SYMBOL_KIND_FUNCTION + /* Some types are also in VAR_DOMAIN. */ + && symbol_kind != GDB_INDEX_SYMBOL_KIND_TYPE) + continue; + break; + case STRUCT_DOMAIN: + if (symbol_kind != GDB_INDEX_SYMBOL_KIND_TYPE) + continue; + break; + case LABEL_DOMAIN: + if (symbol_kind != GDB_INDEX_SYMBOL_KIND_OTHER) + continue; + break; + default: + break; } } + + ++iter->next; + return per_cu; } + + return NULL; } -static void -dw2_pre_expand_symtabs_matching (struct objfile *objfile, - enum block_enum block_kind, const char *name, - domain_enum domain) +static struct symtab * +dw2_lookup_symbol (struct objfile *objfile, int block_index, + const char *name, domain_enum domain) { - dw2_do_expand_symtabs_matching (objfile, name); + struct symtab *stab_best = NULL; + struct mapped_index *index; + + dw2_setup (objfile); + + index = dwarf2_per_objfile->index_table; + + /* index is NULL if OBJF_READNOW. */ + if (index) + { + struct dw2_symtab_iterator iter; + struct dwarf2_per_cu_data *per_cu; + + dw2_symtab_iter_init (&iter, index, 1, block_index, domain, name); + + while ((per_cu = dw2_symtab_iter_next (&iter)) != NULL) + { + struct symbol *sym = NULL; + struct symtab *stab = dw2_instantiate_symtab (per_cu); + + /* Some caution must be observed with overloaded functions + and methods, since the index will not contain any overload + information (but NAME might contain it). */ + if (stab->primary) + { + struct blockvector *bv = BLOCKVECTOR (stab); + struct block *block = BLOCKVECTOR_BLOCK (bv, block_index); + + sym = lookup_block_symbol (block, name, domain); + } + + if (sym && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0) + { + if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) + return stab; + + stab_best = stab; + } + + /* Keep looking through other CUs. */ + } + } + + return stab_best; } static void @@ -2611,7 +3285,7 @@ dw2_print_stats (struct objfile *objfile) dw2_setup (objfile); count = 0; for (i = 0; i < (dwarf2_per_objfile->n_comp_units - + dwarf2_per_objfile->n_type_comp_units); ++i) + + dwarf2_per_objfile->n_type_units); ++i) { struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); @@ -2638,7 +3312,25 @@ static void dw2_expand_symtabs_for_function (struct objfile *objfile, const char *func_name) { - dw2_do_expand_symtabs_matching (objfile, func_name); + struct mapped_index *index; + + dw2_setup (objfile); + + index = dwarf2_per_objfile->index_table; + + /* index is NULL if OBJF_READNOW. */ + if (index) + { + struct dw2_symtab_iterator iter; + struct dwarf2_per_cu_data *per_cu; + + /* Note: It doesn't matter what we pass for block_index here. */ + dw2_symtab_iter_init (&iter, index, 0, GLOBAL_BLOCK, VAR_DOMAIN, + func_name); + + while ((per_cu = dw2_symtab_iter_next (&iter)) != NULL) + dw2_instantiate_symtab (per_cu); + } } static void @@ -2649,17 +3341,17 @@ dw2_expand_all_symtabs (struct objfile *objfile) dw2_setup (objfile); for (i = 0; i < (dwarf2_per_objfile->n_comp_units - + dwarf2_per_objfile->n_type_comp_units); ++i) + + dwarf2_per_objfile->n_type_units); ++i) { struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); - dw2_instantiate_symtab (objfile, per_cu); + dw2_instantiate_symtab (per_cu); } } static void -dw2_expand_symtabs_with_filename (struct objfile *objfile, - const char *filename) +dw2_expand_symtabs_with_fullname (struct objfile *objfile, + const char *fullname) { int i; @@ -2686,22 +3378,44 @@ dw2_expand_symtabs_with_filename (struct objfile *objfile, for (j = 0; j < file_data->num_file_names; ++j) { - const char *this_name = file_data->file_names[j]; - if (FILENAME_CMP (this_name, filename) == 0) + const char *this_fullname = file_data->file_names[j]; + + if (filename_cmp (this_fullname, fullname) == 0) { - dw2_instantiate_symtab (objfile, per_cu); + dw2_instantiate_symtab (per_cu); break; } } } } +/* A helper function for dw2_find_symbol_file that finds the primary + file name for a given CU. This is a die_reader_func. */ + +static void +dw2_get_primary_filename_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data) +{ + const char **result_ptr = data; + struct dwarf2_cu *cu = reader->cu; + struct attribute *attr; + + attr = dwarf2_attr (comp_unit_die, DW_AT_name, cu); + if (attr == NULL) + *result_ptr = NULL; + else + *result_ptr = DW_STRING (attr); +} + static const char * dw2_find_symbol_file (struct objfile *objfile, const char *name) { struct dwarf2_per_cu_data *per_cu; offset_type *vec; - struct quick_file_names *file_data; + const char *filename; dw2_setup (objfile); @@ -2710,16 +3424,18 @@ dw2_find_symbol_file (struct objfile *objfile, const char *name) { struct symtab *s; - ALL_OBJFILE_SYMTABS (objfile, s) - if (s->primary) - { - struct blockvector *bv = BLOCKVECTOR (s); - const struct block *block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - struct symbol *sym = lookup_block_symbol (block, name, VAR_DOMAIN); + ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s) + { + struct blockvector *bv = BLOCKVECTOR (s); + const struct block *block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + struct symbol *sym = lookup_block_symbol (block, name, VAR_DOMAIN); - if (sym) - return sym->symtab->filename; - } + if (sym) + { + /* Only file extension of returned filename is recognized. */ + return SYMBOL_SYMTAB (sym)->filename; + } + } return NULL; } @@ -2732,13 +3448,19 @@ dw2_find_symbol_file (struct objfile *objfile, const char *name) should be rewritten so that it doesn't require a custom hook. It could just use the ordinary symbol tables. */ /* vec[0] is the length, which must always be >0. */ - per_cu = dw2_get_cu (MAYBE_SWAP (vec[1])); + per_cu = dw2_get_cu (GDB_INDEX_CU_VALUE (MAYBE_SWAP (vec[1]))); - file_data = dw2_get_file_names (objfile, per_cu); - if (file_data == NULL) - return NULL; + if (per_cu->v.quick->symtab != NULL) + { + /* Only file extension of returned filename is recognized. */ + return per_cu->v.quick->symtab->filename; + } + + init_cutu_and_read_dies (per_cu, NULL, 0, 0, + dw2_get_primary_filename_reader, &filename); - return file_data->file_names[file_data->num_file_names - 1]; + /* Only file extension of returned filename is recognized. */ + return filename; } static void @@ -2757,8 +3479,8 @@ dw2_map_matching_symbols (const char * name, domain_enum namespace, static void dw2_expand_symtabs_matching (struct objfile *objfile, - int (*file_matcher) (const char *, void *), - int (*name_matcher) (const struct language_defn *, const char *, void *), + int (*file_matcher) (const char *, void *, int basenames), + int (*name_matcher) (const char *, void *), enum search_domain kind, void *data) { @@ -2774,32 +3496,81 @@ dw2_expand_symtabs_matching index = dwarf2_per_objfile->index_table; if (file_matcher != NULL) - for (i = 0; i < (dwarf2_per_objfile->n_comp_units - + dwarf2_per_objfile->n_type_comp_units); ++i) - { - int j; - struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); - struct quick_file_names *file_data; + { + struct cleanup *cleanup; + htab_t visited_found, visited_not_found; - per_cu->v.quick->mark = 0; + visited_found = htab_create_alloc (10, + htab_hash_pointer, htab_eq_pointer, + NULL, xcalloc, xfree); + cleanup = make_cleanup_htab_delete (visited_found); + visited_not_found = htab_create_alloc (10, + htab_hash_pointer, htab_eq_pointer, + NULL, xcalloc, xfree); + make_cleanup_htab_delete (visited_not_found); - /* We only need to look at symtabs not already expanded. */ - if (per_cu->v.quick->symtab) - continue; + /* The rule is CUs specify all the files, including those used by + any TU, so there's no need to scan TUs here. */ - file_data = dw2_get_file_names (objfile, per_cu); - if (file_data == NULL) - continue; + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + int j; + struct dwarf2_per_cu_data *per_cu = dw2_get_primary_cu (i); + struct quick_file_names *file_data; + void **slot; - for (j = 0; j < file_data->num_file_names; ++j) - { - if (file_matcher (file_data->file_names[j], data)) - { - per_cu->v.quick->mark = 1; - break; - } - } - } + per_cu->v.quick->mark = 0; + + /* We only need to look at symtabs not already expanded. */ + if (per_cu->v.quick->symtab) + continue; + + file_data = dw2_get_file_names (objfile, per_cu); + if (file_data == NULL) + continue; + + if (htab_find (visited_not_found, file_data) != NULL) + continue; + else if (htab_find (visited_found, file_data) != NULL) + { + per_cu->v.quick->mark = 1; + continue; + } + + for (j = 0; j < file_data->num_file_names; ++j) + { + const char *this_real_name; + + if (file_matcher (file_data->file_names[j], data, 0)) + { + per_cu->v.quick->mark = 1; + break; + } + + /* Before we invoke realpath, which can get expensive when many + files are involved, do a quick comparison of the basenames. */ + if (!basenames_may_differ + && !file_matcher (lbasename (file_data->file_names[j]), + data, 1)) + continue; + + this_real_name = dw2_get_real_path (objfile, file_data, j); + if (file_matcher (this_real_name, data, 0)) + { + per_cu->v.quick->mark = 1; + break; + } + } + + slot = htab_find_slot (per_cu->v.quick->mark + ? visited_found + : visited_not_found, + file_data, INSERT); + *slot = file_data; + } + + do_cleanups (cleanup); + } for (iter = 0; iter < index->symbol_table_slots; ++iter) { @@ -2812,7 +3583,7 @@ dw2_expand_symtabs_matching name = index->constant_pool + MAYBE_SWAP (index->symbol_table[idx]); - if (! (*name_matcher) (current_language, name, data)) + if (! (*name_matcher) (name, data)) continue; /* The name was matched, now expand corresponding CUs that were @@ -2823,14 +3594,73 @@ dw2_expand_symtabs_matching for (vec_idx = 0; vec_idx < vec_len; ++vec_idx) { struct dwarf2_per_cu_data *per_cu; + offset_type cu_index_and_attrs = MAYBE_SWAP (vec[vec_idx + 1]); + gdb_index_symbol_kind symbol_kind = + GDB_INDEX_SYMBOL_KIND_VALUE (cu_index_and_attrs); + int cu_index = GDB_INDEX_CU_VALUE (cu_index_and_attrs); + + /* Don't crash on bad data. */ + if (cu_index >= (dwarf2_per_objfile->n_comp_units + + dwarf2_per_objfile->n_type_units)) + continue; + + /* Only check the symbol's kind if it has one. + Indices prior to version 7 don't record it. */ + if (index->version >= 7) + { + switch (kind) + { + case VARIABLES_DOMAIN: + if (symbol_kind != GDB_INDEX_SYMBOL_KIND_VARIABLE) + continue; + break; + case FUNCTIONS_DOMAIN: + if (symbol_kind != GDB_INDEX_SYMBOL_KIND_FUNCTION) + continue; + break; + case TYPES_DOMAIN: + if (symbol_kind != GDB_INDEX_SYMBOL_KIND_TYPE) + continue; + break; + default: + break; + } + } - per_cu = dw2_get_cu (MAYBE_SWAP (vec[vec_idx + 1])); + per_cu = dw2_get_cu (cu_index); if (file_matcher == NULL || per_cu->v.quick->mark) - dw2_instantiate_symtab (objfile, per_cu); + dw2_instantiate_symtab (per_cu); } } } +/* A helper for dw2_find_pc_sect_symtab which finds the most specific + symtab. */ + +static struct symtab * +recursively_find_pc_sect_symtab (struct symtab *symtab, CORE_ADDR pc) +{ + int i; + + if (BLOCKVECTOR (symtab) != NULL + && blockvector_contains_pc (BLOCKVECTOR (symtab), pc)) + return symtab; + + if (symtab->includes == NULL) + return NULL; + + for (i = 0; symtab->includes[i]; ++i) + { + struct symtab *s = symtab->includes[i]; + + s = recursively_find_pc_sect_symtab (s, pc); + if (s != NULL) + return s; + } + + return NULL; +} + static struct symtab * dw2_find_pc_sect_symtab (struct objfile *objfile, struct minimal_symbol *msymbol, @@ -2839,6 +3669,7 @@ dw2_find_pc_sect_symtab (struct objfile *objfile, int warn_if_readin) { struct dwarf2_per_cu_data *data; + struct symtab *result; dw2_setup (objfile); @@ -2853,7 +3684,9 @@ dw2_find_pc_sect_symtab (struct objfile *objfile, warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"), paddress (get_objfile_arch (objfile), pc)); - return dw2_instantiate_symtab (objfile, data); + result = recursively_find_pc_sect_symtab (dw2_instantiate_symtab (data), pc); + gdb_assert (result != NULL); + return result; } static void @@ -2861,15 +3694,36 @@ dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun, void *data, int need_fullname) { int i; + struct cleanup *cleanup; + htab_t visited = htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer, + NULL, xcalloc, xfree); + cleanup = make_cleanup_htab_delete (visited); dw2_setup (objfile); - for (i = 0; i < (dwarf2_per_objfile->n_comp_units - + dwarf2_per_objfile->n_type_comp_units); ++i) + /* The rule is CUs specify all the files, including those used by + any TU, so there's no need to scan TUs here. + We can ignore file names coming from already-expanded CUs. */ + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) { - int j; struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); + + if (per_cu->v.quick->symtab) + { + void **slot = htab_find_slot (visited, per_cu->v.quick->file_names, + INSERT); + + *slot = per_cu->v.quick->file_names; + } + } + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + int j; + struct dwarf2_per_cu_data *per_cu = dw2_get_primary_cu (i); struct quick_file_names *file_data; + void **slot; /* We only need to look at symtabs not already expanded. */ if (per_cu->v.quick->symtab) @@ -2879,6 +3733,14 @@ dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun, if (file_data == NULL) continue; + slot = htab_find_slot (visited, file_data, INSERT); + if (*slot) + { + /* Already visited. */ + continue; + } + *slot = file_data; + for (j = 0; j < file_data->num_file_names; ++j) { const char *this_real_name; @@ -2890,6 +3752,8 @@ dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun, (*fun) (file_data->file_names[j], this_real_name, data); } } + + do_cleanups (cleanup); } static int @@ -2905,13 +3769,12 @@ const struct quick_symbol_functions dwarf2_gdb_index_functions = dw2_forget_cached_source_info, dw2_map_symtabs_matching_filename, dw2_lookup_symbol, - dw2_pre_expand_symtabs_matching, dw2_print_stats, dw2_dump, dw2_relocate, dw2_expand_symtabs_for_function, dw2_expand_all_symtabs, - dw2_expand_symtabs_with_filename, + dw2_expand_symtabs_with_fullname, dw2_find_symbol_file, dw2_map_matching_symbols, dw2_expand_symtabs_matching, @@ -2935,12 +3798,12 @@ dwarf2_initialize_objfile (struct objfile *objfile) dwarf2_per_objfile->using_index = 1; create_all_comp_units (objfile); - create_debug_types_hash_table (objfile); + create_all_type_units (objfile); dwarf2_per_objfile->quick_file_names_table = create_quick_file_names_table (dwarf2_per_objfile->n_comp_units); for (i = 0; i < (dwarf2_per_objfile->n_comp_units - + dwarf2_per_objfile->n_type_comp_units); ++i) + + dwarf2_per_objfile->n_type_units); ++i) { struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); @@ -2967,25 +3830,75 @@ dwarf2_initialize_objfile (struct objfile *objfile) void dwarf2_build_psymtabs (struct objfile *objfile) { + volatile struct gdb_exception except; + if (objfile->global_psymbols.size == 0 && objfile->static_psymbols.size == 0) { init_psymbol_list (objfile, 1024); } - dwarf2_build_psymtabs_hard (objfile); + TRY_CATCH (except, RETURN_MASK_ERROR) + { + /* This isn't really ideal: all the data we allocate on the + objfile's obstack is still uselessly kept around. However, + freeing it seems unsafe. */ + struct cleanup *cleanups = make_cleanup_discard_psymtabs (objfile); + + dwarf2_build_psymtabs_hard (objfile); + discard_cleanups (cleanups); + } + if (except.reason < 0) + exception_print (gdb_stderr, except); +} + +/* Return the total length of the CU described by HEADER. */ + +static unsigned int +get_cu_length (const struct comp_unit_head *header) +{ + return header->initial_length_size + header->length; } /* Return TRUE if OFFSET is within CU_HEADER. */ static inline int -offset_in_cu_p (const struct comp_unit_head *cu_header, unsigned int offset) +offset_in_cu_p (const struct comp_unit_head *cu_header, sect_offset offset) +{ + sect_offset bottom = { cu_header->offset.sect_off }; + sect_offset top = { cu_header->offset.sect_off + get_cu_length (cu_header) }; + + return (offset.sect_off >= bottom.sect_off && offset.sect_off < top.sect_off); +} + +/* 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) { - unsigned int bottom = cu_header->offset; - unsigned int top = (cu_header->offset - + cu_header->length - + cu_header->initial_length_size); + struct attribute *attr; - return (offset >= bottom && offset < top); + 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; + } + } } /* Read in the comp unit header information from the debug_info at info_ptr. @@ -3005,8 +3918,8 @@ read_comp_unit_head (struct comp_unit_head *cu_header, info_ptr += bytes_read; cu_header->version = read_2_bytes (abfd, info_ptr); info_ptr += 2; - cu_header->abbrev_offset = read_offset (abfd, info_ptr, cu_header, - &bytes_read); + cu_header->abbrev_offset.sect_off = read_offset (abfd, info_ptr, cu_header, + &bytes_read); info_ptr += bytes_read; cu_header->addr_size = read_1_byte (abfd, info_ptr); info_ptr += 1; @@ -3019,47 +3932,82 @@ read_comp_unit_head (struct comp_unit_head *cu_header, return info_ptr; } -/* Read in a CU header and perform some basic error checking. */ +/* Helper function that returns the proper abbrev section for + THIS_CU. */ -static gdb_byte * -partial_read_comp_unit_head (struct comp_unit_head *header, gdb_byte *info_ptr, - gdb_byte *buffer, unsigned int buffer_size, - bfd *abfd, int is_debug_types_section) +static struct dwarf2_section_info * +get_abbrev_section_for_cu (struct dwarf2_per_cu_data *this_cu) { - gdb_byte *beg_of_comp_unit = info_ptr; + struct dwarf2_section_info *abbrev; - header->offset = beg_of_comp_unit - buffer; + if (this_cu->is_dwz) + abbrev = &dwarf2_get_dwz_file ()->abbrev; + else + abbrev = &dwarf2_per_objfile->abbrev; - info_ptr = read_comp_unit_head (header, info_ptr, abfd); + return abbrev; +} - /* If we're reading a type unit, skip over the signature and - type_offset fields. */ - if (is_debug_types_section) - info_ptr += 8 /*signature*/ + header->offset_size; +/* Subroutine of read_and_check_comp_unit_head and + read_and_check_type_unit_head to simplify them. + Perform various error checking on the header. */ - header->first_die_offset = info_ptr - beg_of_comp_unit; +static void +error_check_comp_unit_head (struct comp_unit_head *header, + struct dwarf2_section_info *section, + struct dwarf2_section_info *abbrev_section) +{ + bfd *abfd = section->asection->owner; + const char *filename = bfd_get_filename (abfd); if (header->version != 2 && header->version != 3 && header->version != 4) error (_("Dwarf Error: wrong version in compilation unit header " "(is %d, should be 2, 3, or 4) [in module %s]"), header->version, - bfd_get_filename (abfd)); + filename); - if (header->abbrev_offset - >= dwarf2_section_size (dwarf2_per_objfile->objfile, - &dwarf2_per_objfile->abbrev)) + if (header->abbrev_offset.sect_off + >= dwarf2_section_size (dwarf2_per_objfile->objfile, abbrev_section)) error (_("Dwarf Error: bad offset (0x%lx) in compilation unit header " "(offset 0x%lx + 6) [in module %s]"), - (long) header->abbrev_offset, - (long) (beg_of_comp_unit - buffer), - bfd_get_filename (abfd)); + (long) header->abbrev_offset.sect_off, (long) header->offset.sect_off, + filename); - if (beg_of_comp_unit + header->length + header->initial_length_size - > buffer + buffer_size) + /* Cast to unsigned long to use 64-bit arithmetic when possible to + avoid potential 32-bit overflow. */ + if (((unsigned long) header->offset.sect_off + get_cu_length (header)) + > section->size) error (_("Dwarf Error: bad length (0x%lx) in compilation unit header " "(offset 0x%lx + 0) [in module %s]"), - (long) header->length, - (long) (beg_of_comp_unit - buffer), - bfd_get_filename (abfd)); + (long) header->length, (long) header->offset.sect_off, + filename); +} + +/* Read in a CU/TU header and perform some basic error checking. + The contents of the header are stored in HEADER. + The result is a pointer to the start of the first DIE. */ + +static gdb_byte * +read_and_check_comp_unit_head (struct comp_unit_head *header, + struct dwarf2_section_info *section, + struct dwarf2_section_info *abbrev_section, + gdb_byte *info_ptr, + int is_debug_types_section) +{ + gdb_byte *beg_of_comp_unit = info_ptr; + bfd *abfd = section->asection->owner; + + header->offset.sect_off = beg_of_comp_unit - section->buffer; + + info_ptr = read_comp_unit_head (header, info_ptr, abfd); + + /* If we're reading a type unit, skip over the signature and + type_offset fields. */ + if (is_debug_types_section) + info_ptr += 8 /*signature*/ + header->offset_size; + + header->first_die_offset.cu_off = info_ptr - beg_of_comp_unit; + + error_check_comp_unit_head (header, section, abbrev_section); return info_ptr; } @@ -3068,35 +4016,72 @@ partial_read_comp_unit_head (struct comp_unit_head *header, gdb_byte *info_ptr, types_ptr. The result is a pointer to one past the end of the header. */ static gdb_byte * -read_type_comp_unit_head (struct comp_unit_head *cu_header, - struct dwarf2_section_info *section, - ULONGEST *signature, - gdb_byte *types_ptr, bfd *abfd) +read_and_check_type_unit_head (struct comp_unit_head *header, + struct dwarf2_section_info *section, + struct dwarf2_section_info *abbrev_section, + gdb_byte *info_ptr, + ULONGEST *signature, + cu_offset *type_offset_in_tu) { - gdb_byte *initial_types_ptr = types_ptr; + gdb_byte *beg_of_comp_unit = info_ptr; + bfd *abfd = section->asection->owner; - dwarf2_read_section (dwarf2_per_objfile->objfile, section); - cu_header->offset = types_ptr - section->buffer; + header->offset.sect_off = beg_of_comp_unit - section->buffer; + + info_ptr = read_comp_unit_head (header, info_ptr, abfd); + + /* If we're reading a type unit, skip over the signature and + type_offset fields. */ + if (signature != NULL) + *signature = read_8_bytes (abfd, info_ptr); + info_ptr += 8; + if (type_offset_in_tu != NULL) + type_offset_in_tu->cu_off = read_offset_1 (abfd, info_ptr, + header->offset_size); + info_ptr += header->offset_size; - types_ptr = read_comp_unit_head (cu_header, types_ptr, abfd); + header->first_die_offset.cu_off = info_ptr - beg_of_comp_unit; - *signature = read_8_bytes (abfd, types_ptr); - types_ptr += 8; - types_ptr += cu_header->offset_size; - cu_header->first_die_offset = types_ptr - initial_types_ptr; + error_check_comp_unit_head (header, section, abbrev_section); - return types_ptr; + return info_ptr; } -/* Allocate a new partial symtab for file named NAME and mark this new - partial symtab as being an include of PST. */ +/* Fetch the abbreviation table offset from a comp or type unit header. */ -static void -dwarf2_create_include_psymtab (char *name, struct partial_symtab *pst, - struct objfile *objfile) +static sect_offset +read_abbrev_offset (struct dwarf2_section_info *section, + sect_offset offset) +{ + bfd *abfd = section->asection->owner; + gdb_byte *info_ptr; + unsigned int length, initial_length_size, offset_size; + sect_offset abbrev_offset; + + dwarf2_read_section (dwarf2_per_objfile->objfile, section); + info_ptr = section->buffer + offset.sect_off; + length = read_initial_length (abfd, info_ptr, &initial_length_size); + offset_size = initial_length_size == 4 ? 4 : 8; + info_ptr += initial_length_size + 2 /*version*/; + abbrev_offset.sect_off = read_offset_1 (abfd, info_ptr, offset_size); + return abbrev_offset; +} + +/* Allocate a new partial symtab for file named NAME and mark this new + partial symtab as being an include of PST. */ + +static void +dwarf2_create_include_psymtab (char *name, struct partial_symtab *pst, + struct objfile *objfile) { struct partial_symtab *subpst = allocate_psymtab (name, objfile); + if (!IS_ABSOLUTE_PATH (subpst->filename)) + { + /* It shares objfile->objfile_obstack. */ + subpst->dirname = pst->dirname; + } + subpst->section_offsets = pst->section_offsets; subpst->textlow = 0; subpst->texthigh = 0; @@ -3127,21 +4112,15 @@ dwarf2_create_include_psymtab (char *name, struct partial_symtab *pst, static void dwarf2_build_include_psymtabs (struct dwarf2_cu *cu, - struct die_info *die, - struct partial_symtab *pst) + struct die_info *die, + struct partial_symtab *pst) { - struct objfile *objfile = cu->objfile; - bfd *abfd = objfile->obfd; struct line_header *lh = NULL; struct attribute *attr; 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); - } + lh = dwarf_decode_line_header (DW_UNSND (attr), cu); if (lh == NULL) return; /* No linetable, so no includes. */ @@ -3152,16 +4131,16 @@ dwarf2_build_include_psymtabs (struct dwarf2_cu *cu, } static hashval_t -hash_type_signature (const void *item) +hash_signatured_type (const void *item) { - const struct signatured_type *type_sig = item; + const struct signatured_type *sig_type = item; /* This drops the top 32 bits of the signature, but is ok for a hash. */ - return type_sig->signature; + return sig_type->signature; } static int -eq_type_signature (const void *item_lhs, const void *item_rhs) +eq_signatured_type (const void *item_lhs, const void *item_rhs) { const struct signatured_type *lhs = item_lhs; const struct signatured_type *rhs = item_rhs; @@ -3175,52 +4154,64 @@ static htab_t allocate_signatured_type_table (struct objfile *objfile) { return htab_create_alloc_ex (41, - hash_type_signature, - eq_type_signature, + hash_signatured_type, + eq_signatured_type, NULL, &objfile->objfile_obstack, hashtab_obstack_allocate, dummy_obstack_deallocate); } -/* A helper function to add a signatured type CU to a list. */ +/* A helper function to add a signatured type CU to a table. */ static int -add_signatured_type_cu_to_list (void **slot, void *datum) +add_signatured_type_cu_to_table (void **slot, void *datum) { struct signatured_type *sigt = *slot; - struct dwarf2_per_cu_data ***datap = datum; + struct signatured_type ***datap = datum; - **datap = &sigt->per_cu; + **datap = sigt; ++*datap; return 1; } /* Create the hash table of all entries in the .debug_types section. - The result is zero if there is an error (e.g. missing .debug_types section), - otherwise non-zero. */ + DWO_FILE is a pointer to the DWO file for .debug_types.dwo, + NULL otherwise. + Note: This function processes DWO files only, not DWP files. + The result is a pointer to the hash table or NULL if there are + no types. */ -static int -create_debug_types_hash_table (struct objfile *objfile) +static htab_t +create_debug_types_hash_table (struct dwo_file *dwo_file, + VEC (dwarf2_section_info_def) *types) { + struct objfile *objfile = dwarf2_per_objfile->objfile; htab_t types_htab = NULL; - struct dwarf2_per_cu_data **iter; int ix; struct dwarf2_section_info *section; + struct dwarf2_section_info *abbrev_section; - if (VEC_empty (dwarf2_section_info_def, dwarf2_per_objfile->types)) - { - dwarf2_per_objfile->signatured_types = NULL; - return 0; - } + if (VEC_empty (dwarf2_section_info_def, types)) + return NULL; + + abbrev_section = (dwo_file != NULL + ? &dwo_file->sections.abbrev + : &dwarf2_per_objfile->abbrev); + + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "Reading .debug_types%s for %s:\n", + dwo_file ? ".dwo" : "", + bfd_get_filename (abbrev_section->asection->owner)); for (ix = 0; - VEC_iterate (dwarf2_section_info_def, dwarf2_per_objfile->types, - ix, section); + VEC_iterate (dwarf2_section_info_def, types, ix, section); ++ix) { + bfd *abfd; gdb_byte *info_ptr, *end_ptr; + struct dwarf2_section_info *abbrev_section; dwarf2_read_section (objfile, section); info_ptr = section->buffer; @@ -3228,110 +4219,166 @@ create_debug_types_hash_table (struct objfile *objfile) if (info_ptr == NULL) continue; + /* We can't set abfd until now because the section may be empty or + not present, in which case section->asection will be NULL. */ + abfd = section->asection->owner; + + if (dwo_file) + abbrev_section = &dwo_file->sections.abbrev; + else + abbrev_section = &dwarf2_per_objfile->abbrev; + if (types_htab == NULL) - types_htab = allocate_signatured_type_table (objfile); + { + if (dwo_file) + types_htab = allocate_dwo_unit_table (objfile); + else + types_htab = allocate_signatured_type_table (objfile); + } - if (dwarf2_die_debug) - fprintf_unfiltered (gdb_stdlog, "Signatured types:\n"); + /* We don't use init_cutu_and_read_dies_simple, or some such, here + because we don't need to read any dies: the signature is in the + header. */ end_ptr = info_ptr + section->size; while (info_ptr < end_ptr) { - unsigned int offset; - unsigned int offset_size; - unsigned int type_offset; - unsigned int length, initial_length_size; - unsigned short version; + sect_offset offset; + cu_offset type_offset_in_tu; ULONGEST signature; - struct signatured_type *type_sig; + struct signatured_type *sig_type; + struct dwo_unit *dwo_tu; void **slot; gdb_byte *ptr = info_ptr; + struct comp_unit_head header; + unsigned int length; - offset = ptr - section->buffer; + offset.sect_off = ptr - section->buffer; /* We need to read the type's signature in order to build the hash - table, but we don't need to read anything else just yet. */ + table, but we don't need anything else just yet. */ - /* Sanity check to ensure entire cu is present. */ - length = read_initial_length (objfile->obfd, ptr, - &initial_length_size); - if (ptr + length + initial_length_size > end_ptr) - { - complaint (&symfile_complaints, - _("debug type entry runs off end " - "of `.debug_types' section, ignored")); - break; - } + ptr = read_and_check_type_unit_head (&header, section, + abbrev_section, ptr, + &signature, &type_offset_in_tu); - offset_size = initial_length_size == 4 ? 4 : 8; - ptr += initial_length_size; - version = bfd_get_16 (objfile->obfd, ptr); - ptr += 2; - ptr += offset_size; /* abbrev offset */ - ptr += 1; /* address size */ - signature = bfd_get_64 (objfile->obfd, ptr); - ptr += 8; - type_offset = read_offset_1 (objfile->obfd, ptr, offset_size); - ptr += offset_size; + length = get_cu_length (&header); /* Skip dummy type units. */ - if (ptr >= end_ptr || peek_abbrev_code (objfile->obfd, ptr) == 0) + if (ptr >= info_ptr + length + || peek_abbrev_code (abfd, ptr) == 0) { - info_ptr = info_ptr + initial_length_size + length; + info_ptr += length; continue; } - type_sig = obstack_alloc (&objfile->objfile_obstack, sizeof (*type_sig)); - memset (type_sig, 0, sizeof (*type_sig)); - type_sig->signature = signature; - type_sig->type_offset = type_offset; - type_sig->per_cu.objfile = objfile; - type_sig->per_cu.debug_types_section = section; - type_sig->per_cu.offset = offset; + if (dwo_file) + { + sig_type = NULL; + dwo_tu = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwo_unit); + dwo_tu->dwo_file = dwo_file; + dwo_tu->signature = signature; + dwo_tu->type_offset_in_tu = type_offset_in_tu; + dwo_tu->info_or_types_section = section; + dwo_tu->offset = offset; + dwo_tu->length = length; + } + else + { + /* N.B.: type_offset is not usable if this type uses a DWO file. + The real type_offset is in the DWO file. */ + dwo_tu = NULL; + sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct signatured_type); + sig_type->signature = signature; + sig_type->type_offset_in_tu = type_offset_in_tu; + sig_type->per_cu.objfile = objfile; + sig_type->per_cu.is_debug_types = 1; + sig_type->per_cu.info_or_types_section = section; + sig_type->per_cu.offset = offset; + sig_type->per_cu.length = length; + } - slot = htab_find_slot (types_htab, type_sig, INSERT); + slot = htab_find_slot (types_htab, + dwo_file ? (void*) dwo_tu : (void *) sig_type, + INSERT); gdb_assert (slot != NULL); if (*slot != NULL) { - const struct signatured_type *dup_sig = *slot; + sect_offset dup_offset; + + if (dwo_file) + { + const struct dwo_unit *dup_tu = *slot; + + dup_offset = dup_tu->offset; + } + else + { + const struct signatured_type *dup_tu = *slot; + + dup_offset = dup_tu->per_cu.offset; + } complaint (&symfile_complaints, _("debug type entry at offset 0x%x is duplicate to the " "entry at offset 0x%x, signature 0x%s"), - offset, dup_sig->per_cu.offset, + offset.sect_off, dup_offset.sect_off, phex (signature, sizeof (signature))); - gdb_assert (signature == dup_sig->signature); } - *slot = type_sig; + *slot = dwo_file ? (void *) dwo_tu : (void *) sig_type; - if (dwarf2_die_debug) + if (dwarf2_read_debug) fprintf_unfiltered (gdb_stdlog, " offset 0x%x, signature 0x%s\n", - offset, phex (signature, sizeof (signature))); + offset.sect_off, + phex (signature, sizeof (signature))); - info_ptr = info_ptr + initial_length_size + length; + info_ptr += length; } } + return types_htab; +} + +/* Create the hash table of all entries in the .debug_types section, + and initialize all_type_units. + The result is zero if there is an error (e.g. missing .debug_types section), + otherwise non-zero. */ + +static int +create_all_type_units (struct objfile *objfile) +{ + htab_t types_htab; + struct signatured_type **iter; + + types_htab = create_debug_types_hash_table (NULL, dwarf2_per_objfile->types); + if (types_htab == NULL) + { + dwarf2_per_objfile->signatured_types = NULL; + return 0; + } + dwarf2_per_objfile->signatured_types = types_htab; - dwarf2_per_objfile->n_type_comp_units = htab_elements (types_htab); - dwarf2_per_objfile->type_comp_units + dwarf2_per_objfile->n_type_units = htab_elements (types_htab); + dwarf2_per_objfile->all_type_units = obstack_alloc (&objfile->objfile_obstack, - dwarf2_per_objfile->n_type_comp_units - * sizeof (struct dwarf2_per_cu_data *)); - iter = &dwarf2_per_objfile->type_comp_units[0]; - htab_traverse_noresize (types_htab, add_signatured_type_cu_to_list, &iter); - gdb_assert (iter - &dwarf2_per_objfile->type_comp_units[0] - == dwarf2_per_objfile->n_type_comp_units); + dwarf2_per_objfile->n_type_units + * sizeof (struct signatured_type *)); + iter = &dwarf2_per_objfile->all_type_units[0]; + htab_traverse_noresize (types_htab, add_signatured_type_cu_to_table, &iter); + gdb_assert (iter - &dwarf2_per_objfile->all_type_units[0] + == dwarf2_per_objfile->n_type_units); return 1; } -/* Lookup a signature based type. - Returns NULL if SIG is not present in the table. */ +/* Lookup a signature based type for DW_FORM_ref_sig8. + Returns NULL if signature SIG is not present in the table. */ static struct signatured_type * -lookup_signatured_type (struct objfile *objfile, ULONGEST sig) +lookup_signatured_type (ULONGEST sig) { struct signatured_type find_entry, *entry; @@ -3339,1109 +4386,1919 @@ lookup_signatured_type (struct objfile *objfile, ULONGEST sig) { complaint (&symfile_complaints, _("missing `.debug_types' section for DW_FORM_ref_sig8 die")); - return 0; + return NULL; } find_entry.signature = sig; entry = htab_find (dwarf2_per_objfile->signatured_types, &find_entry); return entry; } + +/* Low level DIE reading support. */ /* Initialize a die_reader_specs struct from a dwarf2_cu struct. */ static void init_cu_die_reader (struct die_reader_specs *reader, - struct dwarf2_cu *cu) + struct dwarf2_cu *cu, + struct dwarf2_section_info *section, + struct dwo_file *dwo_file) { - reader->abfd = cu->objfile->obfd; + gdb_assert (section->readin && section->buffer != NULL); + reader->abfd = section->asection->owner; reader->cu = cu; - if (cu->per_cu->debug_types_section) - { - gdb_assert (cu->per_cu->debug_types_section->readin); - reader->buffer = cu->per_cu->debug_types_section->buffer; - } - else - { - gdb_assert (dwarf2_per_objfile->info.readin); - reader->buffer = dwarf2_per_objfile->info.buffer; - } + reader->dwo_file = dwo_file; + reader->die_section = section; + reader->buffer = section->buffer; + reader->buffer_end = section->buffer + section->size; } -/* 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. */ +/* Initialize a CU (or TU) and read its DIEs. + If the CU defers to a DWO file, read the DWO file as well. + + ABBREV_TABLE, if non-NULL, is the abbreviation table to use. + Otherwise the table specified in the comp unit header is read in and used. + This is an optimization for when we already have the abbrev table. + + If USE_EXISTING_CU is non-zero, and THIS_CU->cu is non-NULL, then use it. + Otherwise, a new CU is allocated with xmalloc. + + If KEEP is non-zero, then if we allocated a dwarf2_cu we add it to + read_in_chain. Otherwise the dwarf2_cu data is freed at the end. + + WARNING: If THIS_CU is a "dummy CU" (used as filler by the incremental + linker) then DIE_READER_FUNC will not get called. */ static void -dwarf2_find_base_address (struct die_info *die, struct dwarf2_cu *cu) -{ +init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, + struct abbrev_table *abbrev_table, + int use_existing_cu, int keep, + die_reader_func_ftype *die_reader_func, + void *data) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_section_info *section = this_cu->info_or_types_section; + bfd *abfd = section->asection->owner; + struct dwarf2_cu *cu; + gdb_byte *begin_info_ptr, *info_ptr; + struct die_reader_specs reader; + struct die_info *comp_unit_die; + int has_children; struct attribute *attr; + struct cleanup *cleanups, *free_cu_cleanup = NULL; + struct signatured_type *sig_type = NULL; + struct dwarf2_section_info *abbrev_section; + /* Non-zero if CU currently points to a DWO file and we need to + reread it. When this happens we need to reread the skeleton die + before we can reread the DWO file. */ + int rereading_dwo_cu = 0; - cu->base_known = 0; - cu->base_address = 0; + if (dwarf2_die_debug) + fprintf_unfiltered (gdb_stdlog, "Reading %s unit at offset 0x%x\n", + this_cu->is_debug_types ? "type" : "comp", + this_cu->offset.sect_off); - attr = dwarf2_attr (die, DW_AT_entry_pc, cu); - if (attr) + if (use_existing_cu) + gdb_assert (keep); + + cleanups = make_cleanup (null_cleanup, NULL); + + /* This is cheap if the section is already read in. */ + dwarf2_read_section (objfile, section); + + begin_info_ptr = info_ptr = section->buffer + this_cu->offset.sect_off; + + abbrev_section = get_abbrev_section_for_cu (this_cu); + + if (use_existing_cu && this_cu->cu != NULL) { - cu->base_address = DW_ADDR (attr); - cu->base_known = 1; + cu = this_cu->cu; + + /* If this CU is from a DWO file we need to start over, we need to + refetch the attributes from the skeleton CU. + This could be optimized by retrieving those attributes from when we + were here the first time: the previous comp_unit_die was stored in + comp_unit_obstack. But there's no data yet that we need this + optimization. */ + if (cu->dwo_unit != NULL) + rereading_dwo_cu = 1; } else { - attr = dwarf2_attr (die, DW_AT_low_pc, cu); - if (attr) - { - cu->base_address = DW_ADDR (attr); - cu->base_known = 1; - } - } -} + /* If !use_existing_cu, this_cu->cu must be NULL. */ + gdb_assert (this_cu->cu == NULL); -/* Subroutine of process_type_comp_unit and dwarf2_build_psymtabs_hard - to combine the common parts. - Process a compilation unit for a psymtab. - BUFFER is a pointer to the beginning of the dwarf section buffer, - either .debug_info or debug_types. - INFO_PTR is a pointer to the start of the CU. - Returns a pointer to the next CU. */ + cu = xmalloc (sizeof (*cu)); + init_one_comp_unit (cu, this_cu); -static gdb_byte * -process_psymtab_comp_unit (struct objfile *objfile, - struct dwarf2_per_cu_data *this_cu, - gdb_byte *buffer, gdb_byte *info_ptr, - unsigned int buffer_size) -{ - bfd *abfd = objfile->obfd; - gdb_byte *beg_of_comp_unit = info_ptr; - struct die_info *comp_unit_die; - struct partial_symtab *pst; - CORE_ADDR baseaddr; - struct cleanup *back_to_inner; - struct dwarf2_cu cu; - int has_children, has_pc_info; - struct attribute *attr; - CORE_ADDR best_lowpc = 0, best_highpc = 0; - struct die_reader_specs reader_specs; - const char *filename; + /* If an error occurs while loading, release our storage. */ + free_cu_cleanup = make_cleanup (free_heap_comp_unit, cu); + } - init_one_comp_unit (&cu, objfile); - back_to_inner = make_cleanup (free_stack_comp_unit, &cu); + if (cu->header.first_die_offset.cu_off != 0 && ! rereading_dwo_cu) + { + /* We already have the header, there's no need to read it in again. */ + info_ptr += cu->header.first_die_offset.cu_off; + } + else + { + if (this_cu->is_debug_types) + { + ULONGEST signature; + cu_offset type_offset_in_tu; + + info_ptr = read_and_check_type_unit_head (&cu->header, section, + abbrev_section, info_ptr, + &signature, + &type_offset_in_tu); + + /* Since per_cu is the first member of struct signatured_type, + we can go from a pointer to one to a pointer to the other. */ + sig_type = (struct signatured_type *) this_cu; + gdb_assert (sig_type->signature == signature); + gdb_assert (sig_type->type_offset_in_tu.cu_off + == type_offset_in_tu.cu_off); + gdb_assert (this_cu->offset.sect_off == cu->header.offset.sect_off); + + /* LENGTH has not been set yet for type units if we're + using .gdb_index. */ + this_cu->length = get_cu_length (&cu->header); + + /* Establish the type offset that can be used to lookup the type. */ + sig_type->type_offset_in_section.sect_off = + this_cu->offset.sect_off + sig_type->type_offset_in_tu.cu_off; + } + else + { + info_ptr = read_and_check_comp_unit_head (&cu->header, section, + abbrev_section, + info_ptr, 0); - info_ptr = partial_read_comp_unit_head (&cu.header, info_ptr, - buffer, buffer_size, - abfd, - this_cu->debug_types_section != NULL); + gdb_assert (this_cu->offset.sect_off == cu->header.offset.sect_off); + gdb_assert (this_cu->length == get_cu_length (&cu->header)); + } + } /* Skip dummy compilation units. */ - if (info_ptr >= buffer + buffer_size + if (info_ptr >= begin_info_ptr + this_cu->length || peek_abbrev_code (abfd, info_ptr) == 0) { - info_ptr = (beg_of_comp_unit + cu.header.length - + cu.header.initial_length_size); - do_cleanups (back_to_inner); - return info_ptr; + do_cleanups (cleanups); + return; } - cu.list_in_scope = &file_symbols; - - /* If this compilation unit was already read in, free the - cached copy in order to read it in again. This is - necessary because we skipped some symbols when we first - read in the compilation unit (see load_partial_dies). - This problem could be avoided, but the benefit is - unclear. */ - if (this_cu->cu != NULL) - free_one_cached_comp_unit (this_cu->cu); - - /* Note that this is a pointer to our stack frame, being - added to a global data structure. It will be cleaned up - in free_stack_comp_unit when we finish with this - compilation unit. */ - this_cu->cu = &cu; - cu.per_cu = this_cu; - - /* Read the abbrevs for this compilation unit into a table. */ - dwarf2_read_abbrevs (abfd, &cu); - make_cleanup (dwarf2_free_abbrev_table, &cu); - - /* Read the compilation unit die. */ - init_cu_die_reader (&reader_specs, &cu); - info_ptr = read_full_die (&reader_specs, &comp_unit_die, info_ptr, - &has_children); - - if (this_cu->debug_types_section) + /* If we don't have them yet, read the abbrevs for this compilation unit. + And if we need to read them now, make sure they're freed when we're + done. Note that it's important that if the CU had an abbrev table + on entry we don't free it when we're done: Somewhere up the call stack + it may be in use. */ + if (abbrev_table != NULL) { - /* LENGTH has not been set yet for type units. */ - gdb_assert (this_cu->offset == cu.header.offset); - this_cu->length = cu.header.length + cu.header.initial_length_size; + gdb_assert (cu->abbrev_table == NULL); + gdb_assert (cu->header.abbrev_offset.sect_off + == abbrev_table->offset.sect_off); + cu->abbrev_table = abbrev_table; } - else if (comp_unit_die->tag == DW_TAG_partial_unit) + else if (cu->abbrev_table == NULL) { - info_ptr = (beg_of_comp_unit + cu.header.length - + cu.header.initial_length_size); - do_cleanups (back_to_inner); - return info_ptr; + dwarf2_read_abbrevs (cu, abbrev_section); + make_cleanup (dwarf2_free_abbrev_table, cu); + } + else if (rereading_dwo_cu) + { + dwarf2_free_abbrev_table (cu); + dwarf2_read_abbrevs (cu, abbrev_section); } - prepare_one_comp_unit (&cu, comp_unit_die); - - /* Allocate a new partial symbol table structure. */ - attr = dwarf2_attr (comp_unit_die, DW_AT_name, &cu); - if (attr == NULL || !DW_STRING (attr)) - filename = ""; - else - filename = DW_STRING (attr); - pst = start_psymtab_common (objfile, objfile->section_offsets, - filename, - /* TEXTLOW and TEXTHIGH are set below. */ - 0, - objfile->global_psymbols.next, - objfile->static_psymbols.next); - pst->psymtabs_addrmap_supported = 1; - - attr = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, &cu); - if (attr != NULL) - pst->dirname = DW_STRING (attr); - - pst->read_symtab_private = this_cu; + /* Read the top level CU/TU die. */ + init_cu_die_reader (&reader, cu, section, NULL); + info_ptr = read_full_die (&reader, &comp_unit_die, info_ptr, &has_children); - baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + /* If we have a DWO stub, process it and then read in the DWO file. + Note that if USE_EXISTING_OK != 0, and THIS_CU->cu already contains + a DWO CU, that this test will fail. */ + attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_name, cu); + if (attr) + { + const char *dwo_name = DW_STRING (attr); + const char *comp_dir_string; + struct dwo_unit *dwo_unit; + ULONGEST signature; /* Or dwo_id. */ + struct attribute *comp_dir, *stmt_list, *low_pc, *high_pc, *ranges; + int i,num_extra_attrs; + struct dwarf2_section_info *dwo_abbrev_section; + + if (has_children) + error (_("Dwarf Error: compilation unit with DW_AT_GNU_dwo_name" + " has children (offset 0x%x) [in module %s]"), + this_cu->offset.sect_off, bfd_get_filename (abfd)); + + /* These attributes aren't processed until later: + DW_AT_stmt_list, DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges. + However, the attribute is found in the stub which we won't have later. + In order to not impose this complication on the rest of the code, + we read them here and copy them to the DWO CU/TU die. */ + + /* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the + DWO file. */ + stmt_list = NULL; + if (! this_cu->is_debug_types) + stmt_list = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu); + low_pc = dwarf2_attr (comp_unit_die, DW_AT_low_pc, cu); + high_pc = dwarf2_attr (comp_unit_die, DW_AT_high_pc, cu); + ranges = dwarf2_attr (comp_unit_die, DW_AT_ranges, cu); + comp_dir = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, cu); + + /* There should be a DW_AT_addr_base attribute here (if needed). + We need the value before we can process DW_FORM_GNU_addr_index. */ + cu->addr_base = 0; + attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_addr_base, cu); + if (attr) + cu->addr_base = DW_UNSND (attr); - /* Store the function that reads in the rest of the symbol table. */ - pst->read_symtab = dwarf2_psymtab_to_symtab; + /* There should be a DW_AT_ranges_base attribute here (if needed). + We need the value before we can process DW_AT_ranges. */ + cu->ranges_base = 0; + attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_ranges_base, cu); + if (attr) + cu->ranges_base = DW_UNSND (attr); - this_cu->v.psymtab = pst; + if (this_cu->is_debug_types) + { + gdb_assert (sig_type != NULL); + signature = sig_type->signature; + } + else + { + attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_id, cu); + if (! attr) + error (_("Dwarf Error: missing dwo_id [in module %s]"), + dwo_name); + signature = DW_UNSND (attr); + } - dwarf2_find_base_address (comp_unit_die, &cu); + /* We may need the comp_dir in order to find the DWO file. */ + comp_dir_string = NULL; + if (comp_dir) + comp_dir_string = DW_STRING (comp_dir); - /* Possibly set the default values of LOWPC and HIGHPC from - `DW_AT_ranges'. */ - has_pc_info = dwarf2_get_pc_bounds (comp_unit_die, &best_lowpc, - &best_highpc, &cu, pst); - if (has_pc_info == 1 && best_lowpc < best_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, - best_lowpc + baseaddr, - best_highpc + baseaddr - 1, pst); + if (this_cu->is_debug_types) + dwo_unit = lookup_dwo_type_unit (sig_type, dwo_name, comp_dir_string); + else + dwo_unit = lookup_dwo_comp_unit (this_cu, dwo_name, comp_dir_string, + signature); - /* 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 (has_children) - { - struct partial_die_info *first_die; - CORE_ADDR lowpc, highpc; + if (dwo_unit == NULL) + { + error (_("Dwarf Error: CU at offset 0x%x references unknown DWO" + " with ID %s [in module %s]"), + this_cu->offset.sect_off, + phex (signature, sizeof (signature)), + objfile->name); + } - lowpc = ((CORE_ADDR) -1); - highpc = ((CORE_ADDR) 0); + /* Set up for reading the DWO CU/TU. */ + cu->dwo_unit = dwo_unit; + section = dwo_unit->info_or_types_section; + dwarf2_read_section (objfile, section); + begin_info_ptr = info_ptr = section->buffer + dwo_unit->offset.sect_off; + dwo_abbrev_section = &dwo_unit->dwo_file->sections.abbrev; + init_cu_die_reader (&reader, cu, section, dwo_unit->dwo_file); - first_die = load_partial_dies (abfd, buffer, info_ptr, 1, &cu); + if (this_cu->is_debug_types) + { + ULONGEST signature; + cu_offset type_offset_in_tu; + + info_ptr = read_and_check_type_unit_head (&cu->header, section, + dwo_abbrev_section, + info_ptr, + &signature, + &type_offset_in_tu); + gdb_assert (sig_type->signature == signature); + gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off); + /* For DWOs coming from DWP files, we don't know the CU length + nor the type's offset in the TU until now. */ + dwo_unit->length = get_cu_length (&cu->header); + dwo_unit->type_offset_in_tu = type_offset_in_tu; + + /* Establish the type offset that can be used to lookup the type. + For DWO files, we don't know it until now. */ + sig_type->type_offset_in_section.sect_off = + dwo_unit->offset.sect_off + dwo_unit->type_offset_in_tu.cu_off; + } + else + { + info_ptr = read_and_check_comp_unit_head (&cu->header, section, + dwo_abbrev_section, + info_ptr, 0); + gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off); + /* For DWOs coming from DWP files, we don't know the CU length + until now. */ + dwo_unit->length = get_cu_length (&cu->header); + } - scan_partial_symbols (first_die, &lowpc, &highpc, - ! has_pc_info, &cu); + /* Discard the original CU's abbrev table, and read the DWO's. */ + if (abbrev_table == NULL) + { + dwarf2_free_abbrev_table (cu); + dwarf2_read_abbrevs (cu, dwo_abbrev_section); + } + else + { + dwarf2_read_abbrevs (cu, dwo_abbrev_section); + make_cleanup (dwarf2_free_abbrev_table, cu); + } - /* If we didn't find a lowpc, set it to highpc to avoid - complaints from `maint check'. */ - if (lowpc == ((CORE_ADDR) -1)) - lowpc = highpc; + /* Read in the die, but leave space to copy over the attributes + from the stub. This has the benefit of simplifying the rest of + the code - all the real work is done here. */ + num_extra_attrs = ((stmt_list != NULL) + + (low_pc != NULL) + + (high_pc != NULL) + + (ranges != NULL) + + (comp_dir != NULL)); + info_ptr = read_full_die_1 (&reader, &comp_unit_die, info_ptr, + &has_children, num_extra_attrs); + + /* Copy over the attributes from the stub to the DWO die. */ + i = comp_unit_die->num_attrs; + if (stmt_list != NULL) + comp_unit_die->attrs[i++] = *stmt_list; + if (low_pc != NULL) + comp_unit_die->attrs[i++] = *low_pc; + if (high_pc != NULL) + comp_unit_die->attrs[i++] = *high_pc; + if (ranges != NULL) + comp_unit_die->attrs[i++] = *ranges; + if (comp_dir != NULL) + comp_unit_die->attrs[i++] = *comp_dir; + comp_unit_die->num_attrs += num_extra_attrs; - /* If the compilation unit didn't have an explicit address range, - then use the information extracted from its child dies. */ - if (! has_pc_info) + /* Skip dummy compilation units. */ + if (info_ptr >= begin_info_ptr + dwo_unit->length + || peek_abbrev_code (abfd, info_ptr) == 0) { - best_lowpc = lowpc; - best_highpc = highpc; + do_cleanups (cleanups); + return; } } - 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); - pst->n_static_syms = objfile->static_psymbols.next - - (objfile->static_psymbols.list + pst->statics_offset); - sort_pst_symbols (pst); - info_ptr = (beg_of_comp_unit + cu.header.length - + cu.header.initial_length_size); + die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data); - if (this_cu->debug_types_section) + if (free_cu_cleanup != NULL) { - /* It's not clear we want to do anything with stmt lists here. - Waiting to see what gcc ultimately does. */ - } - else - { - /* 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); - } + if (keep) + { + /* We've successfully allocated this compilation unit. Let our + caller clean it up when finished with it. */ + discard_cleanups (free_cu_cleanup); - do_cleanups (back_to_inner); + /* We can only discard free_cu_cleanup and all subsequent cleanups. + So we have to manually free the abbrev table. */ + dwarf2_free_abbrev_table (cu); - return info_ptr; + /* Link this CU into read_in_chain. */ + this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain; + dwarf2_per_objfile->read_in_chain = this_cu; + } + else + do_cleanups (free_cu_cleanup); + } + + do_cleanups (cleanups); } -/* Traversal function for htab_traverse_noresize. - Process one .debug_types comp-unit. */ +/* Read CU/TU THIS_CU in section SECTION, + but do not follow DW_AT_GNU_dwo_name if present. + DWOP_FILE, if non-NULL, is the DWO/DWP file to read (the caller is assumed + to have already done the lookup to find the DWO/DWP file). -static int -process_type_comp_unit (void **slot, void *info) -{ - struct signatured_type *entry = (struct signatured_type *) *slot; - struct objfile *objfile = (struct objfile *) info; - struct dwarf2_per_cu_data *this_cu; + The caller is required to fill in THIS_CU->section, THIS_CU->offset, and + THIS_CU->is_debug_types, but nothing else. - this_cu = &entry->per_cu; + We fill in THIS_CU->length. - gdb_assert (this_cu->debug_types_section->readin); - process_psymtab_comp_unit (objfile, this_cu, - this_cu->debug_types_section->buffer, - (this_cu->debug_types_section->buffer - + this_cu->offset), - this_cu->debug_types_section->size); + WARNING: If THIS_CU is a "dummy CU" (used as filler by the incremental + linker) then DIE_READER_FUNC will not get called. - return 1; -} - -/* Subroutine of dwarf2_build_psymtabs_hard to simplify it. - Build partial symbol tables for the .debug_types comp-units. */ + THIS_CU->cu is always freed when done. + This is done in order to not leave THIS_CU->cu in a state where we have + to care whether it refers to the "main" CU or the DWO CU. */ static void -build_type_psymtabs (struct objfile *objfile) +init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu, + struct dwarf2_section_info *abbrev_section, + struct dwo_file *dwo_file, + die_reader_func_ftype *die_reader_func, + void *data) { - if (! create_debug_types_hash_table (objfile)) - return; + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_section_info *section = this_cu->info_or_types_section; + bfd *abfd = section->asection->owner; + struct dwarf2_cu cu; + gdb_byte *begin_info_ptr, *info_ptr; + struct die_reader_specs reader; + struct cleanup *cleanups; + struct die_info *comp_unit_die; + int has_children; - htab_traverse_noresize (dwarf2_per_objfile->signatured_types, - process_type_comp_unit, objfile); -} + if (dwarf2_die_debug) + fprintf_unfiltered (gdb_stdlog, "Reading %s unit at offset 0x%x\n", + this_cu->is_debug_types ? "type" : "comp", + this_cu->offset.sect_off); -/* A cleanup function that clears objfile's psymtabs_addrmap field. */ + gdb_assert (this_cu->cu == NULL); -static void -psymtabs_addrmap_cleanup (void *o) -{ - struct objfile *objfile = o; + /* This is cheap if the section is already read in. */ + dwarf2_read_section (objfile, section); - objfile->psymtabs_addrmap = NULL; -} + init_one_comp_unit (&cu, this_cu); -/* Build the partial symbol table by doing a quick pass through the - .debug_info and .debug_abbrev sections. */ + cleanups = make_cleanup (free_stack_comp_unit, &cu); -static void -dwarf2_build_psymtabs_hard (struct objfile *objfile) -{ - gdb_byte *info_ptr; - struct cleanup *back_to, *addrmap_cleanup; - struct obstack temp_obstack; + begin_info_ptr = info_ptr = section->buffer + this_cu->offset.sect_off; + info_ptr = read_and_check_comp_unit_head (&cu.header, section, + abbrev_section, info_ptr, + this_cu->is_debug_types); - dwarf2_per_objfile->reading_partial_symbols = 1; + this_cu->length = get_cu_length (&cu.header); - dwarf2_read_section (objfile, &dwarf2_per_objfile->info); - info_ptr = dwarf2_per_objfile->info.buffer; + /* Skip dummy compilation units. */ + if (info_ptr >= begin_info_ptr + this_cu->length + || peek_abbrev_code (abfd, info_ptr) == 0) + { + do_cleanups (cleanups); + return; + } - /* Any cached compilation units will be linked by the per-objfile - read_in_chain. Make sure to free them when we're done. */ - back_to = make_cleanup (free_cached_comp_units, NULL); + dwarf2_read_abbrevs (&cu, abbrev_section); + make_cleanup (dwarf2_free_abbrev_table, &cu); - build_type_psymtabs (objfile); + init_cu_die_reader (&reader, &cu, section, dwo_file); + info_ptr = read_full_die (&reader, &comp_unit_die, info_ptr, &has_children); - create_all_comp_units (objfile); + die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data); - /* Create a temporary address map on a temporary obstack. We later - copy this to the final obstack. */ - obstack_init (&temp_obstack); - make_cleanup_obstack_free (&temp_obstack); - objfile->psymtabs_addrmap = addrmap_create_mutable (&temp_obstack); - addrmap_cleanup = make_cleanup (psymtabs_addrmap_cleanup, objfile); + do_cleanups (cleanups); +} - /* Since the objects we're extracting from .debug_info vary in - length, only the individual functions to extract them (like - read_comp_unit_head and load_partial_die) can really know whether - the buffer is large enough to hold another complete object. +/* Read a CU/TU, except that this does not look for DW_AT_GNU_dwo_name and + does not lookup the specified DWO file. + This cannot be used to read DWO files. - At the moment, they don't actually check that. If .debug_info - holds just one extra byte after the last compilation unit's dies, - then read_comp_unit_head will happily read off the end of the - buffer. read_partial_die is similarly casual. Those functions - should be fixed. + THIS_CU->cu is always freed when done. + This is done in order to not leave THIS_CU->cu in a state where we have + to care whether it refers to the "main" CU or the DWO CU. + We can revisit this if the data shows there's a performance issue. */ - For this loop condition, simply checking whether there's any data - left at all should be sufficient. */ +static void +init_cutu_and_read_dies_simple (struct dwarf2_per_cu_data *this_cu, + die_reader_func_ftype *die_reader_func, + void *data) +{ + init_cutu_and_read_dies_no_follow (this_cu, + get_abbrev_section_for_cu (this_cu), + NULL, + die_reader_func, data); +} - while (info_ptr < (dwarf2_per_objfile->info.buffer - + dwarf2_per_objfile->info.size)) - { - struct dwarf2_per_cu_data *this_cu; +/* Create a psymtab named NAME and assign it to PER_CU. - this_cu = dwarf2_find_comp_unit (info_ptr - - dwarf2_per_objfile->info.buffer, - objfile); + The caller must fill in the following details: + dirname, textlow, texthigh. */ - info_ptr = process_psymtab_comp_unit (objfile, this_cu, - dwarf2_per_objfile->info.buffer, - info_ptr, - dwarf2_per_objfile->info.size); - } +static struct partial_symtab * +create_partial_symtab (struct dwarf2_per_cu_data *per_cu, const char *name) +{ + struct objfile *objfile = per_cu->objfile; + struct partial_symtab *pst; - objfile->psymtabs_addrmap = addrmap_create_fixed (objfile->psymtabs_addrmap, - &objfile->objfile_obstack); - discard_cleanups (addrmap_cleanup); + pst = start_psymtab_common (objfile, objfile->section_offsets, + name, 0, + objfile->global_psymbols.next, + objfile->static_psymbols.next); - do_cleanups (back_to); + pst->psymtabs_addrmap_supported = 1; + + /* This is the glue that links PST into GDB's symbol API. */ + pst->read_symtab_private = per_cu; + pst->read_symtab = dwarf2_read_symtab; + per_cu->v.psymtab = pst; + + return pst; } -/* Load the partial DIEs for a secondary CU into memory. */ +/* die_reader_func for process_psymtab_comp_unit. */ static void -load_partial_comp_unit (struct dwarf2_per_cu_data *this_cu, - struct objfile *objfile) +process_psymtab_comp_unit_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data) { - bfd *abfd = objfile->obfd; - gdb_byte *info_ptr; - struct die_info *comp_unit_die; - struct dwarf2_cu *cu; - struct cleanup *free_abbrevs_cleanup, *free_cu_cleanup = NULL; - int has_children; - struct die_reader_specs reader_specs; - int read_cu = 0; + struct dwarf2_cu *cu = reader->cu; + struct objfile *objfile = cu->objfile; + struct dwarf2_per_cu_data *per_cu = cu->per_cu; + struct attribute *attr; + CORE_ADDR baseaddr; + CORE_ADDR best_lowpc = 0, best_highpc = 0; + struct partial_symtab *pst; + int has_pc_info; + const char *filename; + int *want_partial_unit_ptr = data; + + if (comp_unit_die->tag == DW_TAG_partial_unit + && (want_partial_unit_ptr == NULL + || !*want_partial_unit_ptr)) + return; + + gdb_assert (! per_cu->is_debug_types); + + prepare_one_comp_unit (cu, comp_unit_die, language_minimal); + + cu->list_in_scope = &file_symbols; + + /* Allocate a new partial symbol table structure. */ + attr = dwarf2_attr (comp_unit_die, DW_AT_name, cu); + if (attr == NULL || !DW_STRING (attr)) + filename = ""; + else + filename = DW_STRING (attr); + + pst = create_partial_symtab (per_cu, filename); + + /* This must be done before calling dwarf2_build_include_psymtabs. */ + attr = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, cu); + if (attr != NULL) + pst->dirname = DW_STRING (attr); - gdb_assert (! this_cu->debug_types_section); + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + dwarf2_find_base_address (comp_unit_die, cu); - gdb_assert (dwarf2_per_objfile->info.readin); - info_ptr = dwarf2_per_objfile->info.buffer + this_cu->offset; + /* Possibly set the default values of LOWPC and HIGHPC from + `DW_AT_ranges'. */ + has_pc_info = dwarf2_get_pc_bounds (comp_unit_die, &best_lowpc, + &best_highpc, cu, pst); + if (has_pc_info == 1 && best_lowpc < best_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, + best_lowpc + baseaddr, + best_highpc + baseaddr - 1, pst); - if (this_cu->cu == NULL) + /* 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 (has_children) { - cu = xmalloc (sizeof (*cu)); - init_one_comp_unit (cu, objfile); + struct partial_die_info *first_die; + CORE_ADDR lowpc, highpc; - read_cu = 1; + lowpc = ((CORE_ADDR) -1); + highpc = ((CORE_ADDR) 0); - /* If an error occurs while loading, release our storage. */ - free_cu_cleanup = make_cleanup (free_one_comp_unit, cu); + first_die = load_partial_dies (reader, info_ptr, 1); - info_ptr = partial_read_comp_unit_head (&cu->header, info_ptr, - dwarf2_per_objfile->info.buffer, - dwarf2_per_objfile->info.size, - abfd, 0); + scan_partial_symbols (first_die, &lowpc, &highpc, + ! has_pc_info, cu); - /* Skip dummy compilation units. */ - if (info_ptr >= (dwarf2_per_objfile->info.buffer - + dwarf2_per_objfile->info.size) - || peek_abbrev_code (abfd, info_ptr) == 0) + /* If we didn't find a lowpc, set it to highpc to avoid + complaints from `maint check'. */ + if (lowpc == ((CORE_ADDR) -1)) + lowpc = highpc; + + /* If the compilation unit didn't have an explicit address range, + then use the information extracted from its child dies. */ + if (! has_pc_info) { - do_cleanups (free_cu_cleanup); - return; + best_lowpc = lowpc; + best_highpc = highpc; } + } + 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); + pst->n_static_syms = objfile->static_psymbols.next - + (objfile->static_psymbols.list + pst->statics_offset); + sort_pst_symbols (objfile, pst); - /* Link this compilation unit into the compilation unit tree. */ - this_cu->cu = cu; - cu->per_cu = this_cu; + if (!VEC_empty (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs)) + { + int i; + int len = VEC_length (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs); + struct dwarf2_per_cu_data *iter; + + /* Fill in 'dependencies' here; we fill in 'users' in a + post-pass. */ + pst->number_of_dependencies = len; + pst->dependencies = obstack_alloc (&objfile->objfile_obstack, + len * sizeof (struct symtab *)); + for (i = 0; + VEC_iterate (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs, + i, iter); + ++i) + pst->dependencies[i] = iter->v.psymtab; - /* Link this CU into read_in_chain. */ - this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain; - dwarf2_per_objfile->read_in_chain = this_cu; + VEC_free (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs); } - else + + /* 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); + + if (dwarf2_read_debug) { - cu = this_cu->cu; - info_ptr += cu->header.first_die_offset; + struct gdbarch *gdbarch = get_objfile_arch (objfile); + + fprintf_unfiltered (gdb_stdlog, + "Psymtab for %s unit @0x%x: %s - %s" + ", %d global, %d static syms\n", + per_cu->is_debug_types ? "type" : "comp", + per_cu->offset.sect_off, + paddress (gdbarch, pst->textlow), + paddress (gdbarch, pst->texthigh), + pst->n_global_syms, pst->n_static_syms); } +} - /* Read the abbrevs for this compilation unit into a table. */ - gdb_assert (cu->dwarf2_abbrevs == NULL); - dwarf2_read_abbrevs (abfd, cu); - free_abbrevs_cleanup = make_cleanup (dwarf2_free_abbrev_table, cu); +/* Subroutine of dwarf2_build_psymtabs_hard to simplify it. + Process compilation unit THIS_CU for a psymtab. */ - /* Read the compilation unit die. */ - init_cu_die_reader (&reader_specs, cu); - info_ptr = read_full_die (&reader_specs, &comp_unit_die, info_ptr, - &has_children); +static void +process_psymtab_comp_unit (struct dwarf2_per_cu_data *this_cu, + int want_partial_unit) +{ + /* If this compilation unit was already read in, free the + cached copy in order to read it in again. This is + necessary because we skipped some symbols when we first + read in the compilation unit (see load_partial_dies). + This problem could be avoided, but the benefit is unclear. */ + if (this_cu->cu != NULL) + free_one_cached_comp_unit (this_cu); - prepare_one_comp_unit (cu, comp_unit_die); + gdb_assert (! this_cu->is_debug_types); + init_cutu_and_read_dies (this_cu, NULL, 0, 0, + process_psymtab_comp_unit_reader, + &want_partial_unit); - /* 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 (has_children) - load_partial_dies (abfd, dwarf2_per_objfile->info.buffer, info_ptr, 0, cu); + /* Age out any secondary CUs. */ + age_cached_comp_units (); +} - do_cleanups (free_abbrevs_cleanup); +static hashval_t +hash_type_unit_group (const void *item) +{ + const struct type_unit_group *tu_group = item; - if (read_cu) - { - /* We've successfully allocated this compilation unit. Let our - caller clean it up when finished with it. */ - discard_cleanups (free_cu_cleanup); - } + return hash_stmt_list_entry (&tu_group->hash); } -/* Create a list of all compilation units in OBJFILE. We do this only - if an inter-comp-unit reference is found; presumably if there is one, - there will be many, and one will occur early in the .debug_info section. - So there's no point in building this list incrementally. */ +static int +eq_type_unit_group (const void *item_lhs, const void *item_rhs) +{ + const struct type_unit_group *lhs = item_lhs; + const struct type_unit_group *rhs = item_rhs; -static void -create_all_comp_units (struct objfile *objfile) + return eq_stmt_list_entry (&lhs->hash, &rhs->hash); +} + +/* Allocate a hash table for type unit groups. */ + +static htab_t +allocate_type_unit_groups_table (void) { - int n_allocated; - int n_comp_units; - struct dwarf2_per_cu_data **all_comp_units; - gdb_byte *info_ptr; + return htab_create_alloc_ex (3, + hash_type_unit_group, + eq_type_unit_group, + NULL, + &dwarf2_per_objfile->objfile->objfile_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); +} - dwarf2_read_section (objfile, &dwarf2_per_objfile->info); - info_ptr = dwarf2_per_objfile->info.buffer; +/* Type units that don't have DW_AT_stmt_list are grouped into their own + partial symtabs. We combine several TUs per psymtab to not let the size + of any one psymtab grow too big. */ +#define NO_STMT_LIST_TYPE_UNIT_PSYMTAB (1 << 31) +#define NO_STMT_LIST_TYPE_UNIT_PSYMTAB_SIZE 10 - n_comp_units = 0; - n_allocated = 10; - all_comp_units = xmalloc (n_allocated - * sizeof (struct dwarf2_per_cu_data *)); +/* Helper routine for get_type_unit_group. + Create the type_unit_group object used to hold one or more TUs. */ - while (info_ptr < dwarf2_per_objfile->info.buffer - + dwarf2_per_objfile->info.size) - { - unsigned int length, initial_length_size; - struct dwarf2_per_cu_data *this_cu; - unsigned int offset; +static struct type_unit_group * +create_type_unit_group (struct dwarf2_cu *cu, sect_offset line_offset_struct) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_per_cu_data *per_cu; + struct type_unit_group *tu_group; - offset = info_ptr - dwarf2_per_objfile->info.buffer; + tu_group = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct type_unit_group); + per_cu = &tu_group->per_cu; + per_cu->objfile = objfile; + per_cu->is_debug_types = 1; + per_cu->type_unit_group = tu_group; - /* Read just enough information to find out where the next - compilation unit is. */ - length = read_initial_length (objfile->obfd, info_ptr, - &initial_length_size); + if (dwarf2_per_objfile->using_index) + { + per_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_per_cu_quick_data); + tu_group->t.first_tu = cu->per_cu; + } + else + { + unsigned int line_offset = line_offset_struct.sect_off; + struct partial_symtab *pst; + char *name; - /* Save the compilation unit for later lookup. */ - this_cu = obstack_alloc (&objfile->objfile_obstack, - sizeof (struct dwarf2_per_cu_data)); - memset (this_cu, 0, sizeof (*this_cu)); - this_cu->offset = offset; - this_cu->length = length + initial_length_size; - this_cu->objfile = objfile; + /* Give the symtab a useful name for debug purposes. */ + if ((line_offset & NO_STMT_LIST_TYPE_UNIT_PSYMTAB) != 0) + name = xstrprintf ("", + (line_offset & ~NO_STMT_LIST_TYPE_UNIT_PSYMTAB)); + else + name = xstrprintf ("", line_offset); - if (n_comp_units == n_allocated) - { - n_allocated *= 2; - all_comp_units = xrealloc (all_comp_units, - n_allocated - * sizeof (struct dwarf2_per_cu_data *)); - } - all_comp_units[n_comp_units++] = this_cu; + pst = create_partial_symtab (per_cu, name); + pst->anonymous = 1; - info_ptr = info_ptr + this_cu->length; + xfree (name); } - dwarf2_per_objfile->all_comp_units - = obstack_alloc (&objfile->objfile_obstack, - n_comp_units * sizeof (struct dwarf2_per_cu_data *)); - memcpy (dwarf2_per_objfile->all_comp_units, all_comp_units, - n_comp_units * sizeof (struct dwarf2_per_cu_data *)); - xfree (all_comp_units); - dwarf2_per_objfile->n_comp_units = n_comp_units; + tu_group->hash.dwo_unit = cu->dwo_unit; + tu_group->hash.line_offset = line_offset_struct; + + return tu_group; } -/* Process all loaded DIEs for compilation unit CU, starting at - FIRST_DIE. The caller should pass NEED_PC == 1 if the compilation - unit DIE did not have PC info (DW_AT_low_pc and DW_AT_high_pc, or - DW_AT_ranges). If NEED_PC is set, then this function will set - *LOWPC and *HIGHPC to the lowest and highest PC values found in CU - and record the covered ranges in the addrmap. */ +/* Look up the type_unit_group for type unit CU, and create it if necessary. + STMT_LIST is a DW_AT_stmt_list attribute. */ -static void -scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc, - CORE_ADDR *highpc, int need_pc, struct dwarf2_cu *cu) +static struct type_unit_group * +get_type_unit_group (struct dwarf2_cu *cu, struct attribute *stmt_list) { - struct partial_die_info *pdi; + struct tu_stats *tu_stats = &dwarf2_per_objfile->tu_stats; + struct type_unit_group *tu_group; + void **slot; + unsigned int line_offset; + struct type_unit_group type_unit_group_for_lookup; - /* Now, march along the PDI's, descending into ones which have - interesting children but skipping the children of the other ones, - until we reach the end of the compilation unit. */ + if (dwarf2_per_objfile->type_unit_groups == NULL) + { + dwarf2_per_objfile->type_unit_groups = + allocate_type_unit_groups_table (); + } - pdi = first_die; + /* Do we need to create a new group, or can we use an existing one? */ - while (pdi != NULL) + if (stmt_list) { - fixup_partial_die (pdi, cu); + line_offset = DW_UNSND (stmt_list); + ++tu_stats->nr_symtab_sharers; + } + else + { + /* Ugh, no stmt_list. Rare, but we have to handle it. + We can do various things here like create one group per TU or + spread them over multiple groups to split up the expansion work. + To avoid worst case scenarios (too many groups or too large groups) + we, umm, group them in bunches. */ + line_offset = (NO_STMT_LIST_TYPE_UNIT_PSYMTAB + | (tu_stats->nr_stmt_less_type_units + / NO_STMT_LIST_TYPE_UNIT_PSYMTAB_SIZE)); + ++tu_stats->nr_stmt_less_type_units; + } + + type_unit_group_for_lookup.hash.dwo_unit = cu->dwo_unit; + type_unit_group_for_lookup.hash.line_offset.sect_off = line_offset; + slot = htab_find_slot (dwarf2_per_objfile->type_unit_groups, + &type_unit_group_for_lookup, INSERT); + if (*slot != NULL) + { + tu_group = *slot; + gdb_assert (tu_group != NULL); + } + else + { + sect_offset line_offset_struct; - /* Anonymous namespaces or modules have no name but have interesting - children, so we need to look at them. Ditto for anonymous - enums. */ + line_offset_struct.sect_off = line_offset; + tu_group = create_type_unit_group (cu, line_offset_struct); + *slot = tu_group; + ++tu_stats->nr_symtabs; + } - if (pdi->name != NULL || pdi->tag == DW_TAG_namespace - || pdi->tag == DW_TAG_module || pdi->tag == DW_TAG_enumeration_type) - { - switch (pdi->tag) - { - case DW_TAG_subprogram: - add_partial_subprogram (pdi, lowpc, highpc, need_pc, cu); - break; - case DW_TAG_constant: - case DW_TAG_variable: - case DW_TAG_typedef: - case DW_TAG_union_type: - if (!pdi->is_declaration) - { - add_partial_symbol (pdi, cu); - } - break; - case DW_TAG_class_type: - case DW_TAG_interface_type: - case DW_TAG_structure_type: - if (!pdi->is_declaration) - { - add_partial_symbol (pdi, cu); - } - break; - case DW_TAG_enumeration_type: - if (!pdi->is_declaration) - add_partial_enumeration (pdi, cu); - break; - case DW_TAG_base_type: - case DW_TAG_subrange_type: - /* File scope base type definitions are added to the partial - symbol table. */ - add_partial_symbol (pdi, cu); - break; - case DW_TAG_namespace: - add_partial_namespace (pdi, lowpc, highpc, need_pc, cu); - break; - case DW_TAG_module: - add_partial_module (pdi, lowpc, highpc, need_pc, cu); - break; - default: - break; - } - } + return tu_group; +} - /* If the die has a sibling, skip to the sibling. */ +/* Struct used to sort TUs by their abbreviation table offset. */ - pdi = pdi->die_sibling; - } +struct tu_abbrev_offset +{ + struct signatured_type *sig_type; + sect_offset abbrev_offset; +}; + +/* Helper routine for build_type_unit_groups, passed to qsort. */ + +static int +sort_tu_by_abbrev_offset (const void *ap, const void *bp) +{ + const struct tu_abbrev_offset * const *a = ap; + const struct tu_abbrev_offset * const *b = bp; + unsigned int aoff = (*a)->abbrev_offset.sect_off; + unsigned int boff = (*b)->abbrev_offset.sect_off; + + return (aoff > boff) - (aoff < boff); } -/* Functions used to compute the fully scoped name of a partial DIE. +/* A helper function to add a type_unit_group to a table. */ - Normally, this is simple. For C++, the parent DIE's fully scoped - name is concatenated with "::" and the partial DIE's name. For - Java, the same thing occurs except that "." is used instead of "::". - Enumerators are an exception; they use the scope of their parent - enumeration type, i.e. the name of the enumeration type is not - prepended to the enumerator. +static int +add_type_unit_group_to_table (void **slot, void *datum) +{ + struct type_unit_group *tu_group = *slot; + struct type_unit_group ***datap = datum; - There are two complexities. One is DW_AT_specification; in this - case "parent" means the parent of the target of the specification, - instead of the direct parent of the DIE. The other is compilers - which do not emit DW_TAG_namespace; in this case we try to guess - the fully qualified name of structure types from their members' - linkage names. This must be done using the DIE's children rather - than the children of any DW_AT_specification target. We only need - to do this for structures at the top level, i.e. if the target of - any DW_AT_specification (if any; otherwise the DIE itself) does not - have a parent. */ + **datap = tu_group; + ++*datap; -/* Compute the scope prefix associated with PDI's parent, in - compilation unit CU. The result will be allocated on CU's - comp_unit_obstack, or a copy of the already allocated PDI->NAME - field. NULL is returned if no prefix is necessary. */ -static char * -partial_die_parent_scope (struct partial_die_info *pdi, - struct dwarf2_cu *cu) + return 1; +} + +/* Efficiently read all the type units, calling init_cutu_and_read_dies on + each one passing FUNC,DATA. + + The efficiency is because we sort TUs by the abbrev table they use and + only read each abbrev table once. In one program there are 200K TUs + sharing 8K abbrev tables. + + The main purpose of this function is to support building the + dwarf2_per_objfile->type_unit_groups table. + TUs typically share the DW_AT_stmt_list of the CU they came from, so we + can collapse the search space by grouping them by stmt_list. + The savings can be significant, in the same program from above the 200K TUs + share 8K stmt_list tables. + + FUNC is expected to call get_type_unit_group, which will create the + struct type_unit_group if necessary and add it to + dwarf2_per_objfile->type_unit_groups. */ + +static void +build_type_unit_groups (die_reader_func_ftype *func, void *data) { - char *grandparent_scope; - struct partial_die_info *parent, *real_pdi; + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct tu_stats *tu_stats = &dwarf2_per_objfile->tu_stats; + struct cleanup *cleanups; + struct abbrev_table *abbrev_table; + sect_offset abbrev_offset; + struct tu_abbrev_offset *sorted_by_abbrev; + struct type_unit_group **iter; + int i; - /* We need to look at our parent DIE; if we have a DW_AT_specification, - then this means the parent of the specification DIE. */ + /* It's up to the caller to not call us multiple times. */ + gdb_assert (dwarf2_per_objfile->type_unit_groups == NULL); - real_pdi = pdi; - while (real_pdi->has_specification) - real_pdi = find_partial_die (real_pdi->spec_offset, cu); + if (dwarf2_per_objfile->n_type_units == 0) + return; - parent = real_pdi->die_parent; - if (parent == NULL) - return NULL; + /* TUs typically share abbrev tables, and there can be way more TUs than + abbrev tables. Sort by abbrev table to reduce the number of times we + read each abbrev table in. + Alternatives are to punt or to maintain a cache of abbrev tables. + This is simpler and efficient enough for now. - if (parent->scope_set) - return parent->scope; + Later we group TUs by their DW_AT_stmt_list value (as this defines the + symtab to use). Typically TUs with the same abbrev offset have the same + stmt_list value too so in practice this should work well. - fixup_partial_die (parent, cu); + The basic algorithm here is: - grandparent_scope = partial_die_parent_scope (parent, cu); + sort TUs by abbrev table + for each TU with same abbrev table: + read abbrev table if first user + read TU top level DIE + [IWBN if DWO skeletons had DW_AT_stmt_list] + call FUNC */ - /* GCC 4.0 and 4.1 had a bug (PR c++/28460) where they generated bogus - DW_TAG_namespace DIEs with a name of "::" for the global namespace. - Work around this problem here. */ - if (cu->language == language_cplus - && parent->tag == DW_TAG_namespace - && strcmp (parent->name, "::") == 0 - && grandparent_scope == NULL) + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "Building type unit groups ...\n"); + + /* Sort in a separate table to maintain the order of all_type_units + for .gdb_index: TU indices directly index all_type_units. */ + sorted_by_abbrev = XNEWVEC (struct tu_abbrev_offset, + dwarf2_per_objfile->n_type_units); + for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i) { - parent->scope = NULL; - parent->scope_set = 1; - return NULL; + struct signatured_type *sig_type = dwarf2_per_objfile->all_type_units[i]; + + sorted_by_abbrev[i].sig_type = sig_type; + sorted_by_abbrev[i].abbrev_offset = + read_abbrev_offset (sig_type->per_cu.info_or_types_section, + sig_type->per_cu.offset); } + cleanups = make_cleanup (xfree, sorted_by_abbrev); + qsort (sorted_by_abbrev, dwarf2_per_objfile->n_type_units, + sizeof (struct tu_abbrev_offset), sort_tu_by_abbrev_offset); - if (pdi->tag == DW_TAG_enumerator) - /* Enumerators should not get the name of the enumeration as a prefix. */ - parent->scope = grandparent_scope; - else if (parent->tag == DW_TAG_namespace - || parent->tag == DW_TAG_module - || parent->tag == DW_TAG_structure_type - || parent->tag == DW_TAG_class_type - || parent->tag == DW_TAG_interface_type - || parent->tag == DW_TAG_union_type - || parent->tag == DW_TAG_enumeration_type) + /* Note: In the .gdb_index case, get_type_unit_group may have already been + called any number of times, so we don't reset tu_stats here. */ + + abbrev_offset.sect_off = ~(unsigned) 0; + abbrev_table = NULL; + make_cleanup (abbrev_table_free_cleanup, &abbrev_table); + + for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i) { - if (grandparent_scope == NULL) - parent->scope = parent->name; - else - parent->scope = typename_concat (&cu->comp_unit_obstack, - grandparent_scope, - parent->name, 0, cu); + const struct tu_abbrev_offset *tu = &sorted_by_abbrev[i]; + + /* Switch to the next abbrev table if necessary. */ + if (abbrev_table == NULL + || tu->abbrev_offset.sect_off != abbrev_offset.sect_off) + { + if (abbrev_table != NULL) + { + abbrev_table_free (abbrev_table); + /* Reset to NULL in case abbrev_table_read_table throws + an error: abbrev_table_free_cleanup will get called. */ + abbrev_table = NULL; + } + abbrev_offset = tu->abbrev_offset; + abbrev_table = + abbrev_table_read_table (&dwarf2_per_objfile->abbrev, + abbrev_offset); + ++tu_stats->nr_uniq_abbrev_tables; + } + + init_cutu_and_read_dies (&tu->sig_type->per_cu, abbrev_table, 0, 0, + func, data); } - else + + /* Create a vector of pointers to primary type units to make it easy to + iterate over them and CUs. See dw2_get_primary_cu. */ + dwarf2_per_objfile->n_type_unit_groups = + htab_elements (dwarf2_per_objfile->type_unit_groups); + dwarf2_per_objfile->all_type_unit_groups = + obstack_alloc (&objfile->objfile_obstack, + dwarf2_per_objfile->n_type_unit_groups + * sizeof (struct type_unit_group *)); + iter = &dwarf2_per_objfile->all_type_unit_groups[0]; + htab_traverse_noresize (dwarf2_per_objfile->type_unit_groups, + add_type_unit_group_to_table, &iter); + gdb_assert (iter - &dwarf2_per_objfile->all_type_unit_groups[0] + == dwarf2_per_objfile->n_type_unit_groups); + + do_cleanups (cleanups); + + if (dwarf2_read_debug) { - /* FIXME drow/2004-04-01: What should we be doing with - function-local names? For partial symbols, we should probably be - ignoring them. */ - complaint (&symfile_complaints, - _("unhandled containing DIE tag %d for DIE at %d"), - parent->tag, pdi->offset); - parent->scope = grandparent_scope; + fprintf_unfiltered (gdb_stdlog, "Done building type unit groups:\n"); + fprintf_unfiltered (gdb_stdlog, " %d TUs\n", + dwarf2_per_objfile->n_type_units); + fprintf_unfiltered (gdb_stdlog, " %d uniq abbrev tables\n", + tu_stats->nr_uniq_abbrev_tables); + fprintf_unfiltered (gdb_stdlog, " %d symtabs from stmt_list entries\n", + tu_stats->nr_symtabs); + fprintf_unfiltered (gdb_stdlog, " %d symtab sharers\n", + tu_stats->nr_symtab_sharers); + fprintf_unfiltered (gdb_stdlog, " %d type units without a stmt_list\n", + tu_stats->nr_stmt_less_type_units); } - - parent->scope_set = 1; - return parent->scope; } -/* Return the fully scoped name associated with PDI, from compilation unit - CU. The result will be allocated with malloc. */ -static char * -partial_die_full_name (struct partial_die_info *pdi, - struct dwarf2_cu *cu) +/* Reader function for build_type_psymtabs. */ + +static void +build_type_psymtabs_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *type_unit_die, + int has_children, + void *data) { - char *parent_scope; + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_cu *cu = reader->cu; + struct dwarf2_per_cu_data *per_cu = cu->per_cu; + struct type_unit_group *tu_group; + struct attribute *attr; + struct partial_die_info *first_die; + CORE_ADDR lowpc, highpc; + struct partial_symtab *pst; - /* If this is a template instantiation, we can not work out the - template arguments from partial DIEs. So, unfortunately, we have - to go through the full DIEs. At least any work we do building - types here will be reused if full symbols are loaded later. */ - if (pdi->has_template_arguments) - { - fixup_partial_die (pdi, cu); + gdb_assert (data == NULL); - if (pdi->name != NULL && strchr (pdi->name, '<') == NULL) - { - struct die_info *die; - struct attribute attr; - struct dwarf2_cu *ref_cu = cu; + if (! has_children) + return; - attr.name = 0; - attr.form = DW_FORM_ref_addr; - attr.u.addr = pdi->offset; - die = follow_die_ref (NULL, &attr, &ref_cu); + attr = dwarf2_attr_no_follow (type_unit_die, DW_AT_stmt_list); + tu_group = get_type_unit_group (cu, attr); - return xstrdup (dwarf2_full_name (NULL, die, ref_cu)); - } + VEC_safe_push (dwarf2_per_cu_ptr, tu_group->t.tus, per_cu); + + prepare_one_comp_unit (cu, type_unit_die, language_minimal); + cu->list_in_scope = &file_symbols; + pst = create_partial_symtab (per_cu, ""); + pst->anonymous = 1; + + first_die = load_partial_dies (reader, info_ptr, 1); + + lowpc = (CORE_ADDR) -1; + highpc = (CORE_ADDR) 0; + scan_partial_symbols (first_die, &lowpc, &highpc, 0, cu); + + pst->n_global_syms = objfile->global_psymbols.next - + (objfile->global_psymbols.list + pst->globals_offset); + pst->n_static_syms = objfile->static_psymbols.next - + (objfile->static_psymbols.list + pst->statics_offset); + sort_pst_symbols (objfile, pst); +} + +/* Traversal function for build_type_psymtabs. */ + +static int +build_type_psymtab_dependencies (void **slot, void *info) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct type_unit_group *tu_group = (struct type_unit_group *) *slot; + struct dwarf2_per_cu_data *per_cu = &tu_group->per_cu; + struct partial_symtab *pst = per_cu->v.psymtab; + int len = VEC_length (dwarf2_per_cu_ptr, tu_group->t.tus); + struct dwarf2_per_cu_data *iter; + int i; + + gdb_assert (len > 0); + + pst->number_of_dependencies = len; + pst->dependencies = obstack_alloc (&objfile->objfile_obstack, + len * sizeof (struct psymtab *)); + for (i = 0; + VEC_iterate (dwarf2_per_cu_ptr, tu_group->t.tus, i, iter); + ++i) + { + pst->dependencies[i] = iter->v.psymtab; + iter->type_unit_group = tu_group; } - parent_scope = partial_die_parent_scope (pdi, cu); - if (parent_scope == NULL) - return NULL; - else - return typename_concat (NULL, parent_scope, pdi->name, 0, cu); + VEC_free (dwarf2_per_cu_ptr, tu_group->t.tus); + + return 1; } +/* Subroutine of dwarf2_build_psymtabs_hard to simplify it. + Build partial symbol tables for the .debug_types comp-units. */ + static void -add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) +build_type_psymtabs (struct objfile *objfile) { - struct objfile *objfile = cu->objfile; - CORE_ADDR addr = 0; - char *actual_name = NULL; - const struct partial_symbol *psym = NULL; - CORE_ADDR baseaddr; - int built_actual_name = 0; + if (! create_all_type_units (objfile)) + return; - baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + build_type_unit_groups (build_type_psymtabs_reader, NULL); - actual_name = partial_die_full_name (pdi, cu); - if (actual_name) - built_actual_name = 1; + /* Now that all TUs have been processed we can fill in the dependencies. */ + htab_traverse_noresize (dwarf2_per_objfile->type_unit_groups, + build_type_psymtab_dependencies, NULL); +} - if (actual_name == NULL) - actual_name = pdi->name; +/* A cleanup function that clears objfile's psymtabs_addrmap field. */ - switch (pdi->tag) +static void +psymtabs_addrmap_cleanup (void *o) +{ + struct objfile *objfile = o; + + objfile->psymtabs_addrmap = NULL; +} + +/* Compute the 'user' field for each psymtab in OBJFILE. */ + +static void +set_partial_user (struct objfile *objfile) +{ + int i; + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) { - case DW_TAG_subprogram: - if (pdi->is_external || cu->language == language_ada) + struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); + struct partial_symtab *pst = per_cu->v.psymtab; + int j; + + if (pst == NULL) + continue; + + for (j = 0; j < pst->number_of_dependencies; ++j) { - /* brobecker/2007-12-26: Normally, only "external" DIEs are part - of the global scope. But in Ada, we want to be able to access - nested procedures globally. So all Ada subprograms are stored - in the global scope. */ - /* prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr, - mst_text, objfile); */ - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, - VAR_DOMAIN, LOC_BLOCK, - &objfile->global_psymbols, - 0, pdi->lowpc + baseaddr, - cu->language, objfile); - } - else - { - /* prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr, - mst_file_text, objfile); */ - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, - VAR_DOMAIN, LOC_BLOCK, - &objfile->static_psymbols, - 0, pdi->lowpc + baseaddr, - cu->language, objfile); + /* Set the 'user' field only if it is not already set. */ + if (pst->dependencies[j]->user == NULL) + pst->dependencies[j]->user = pst; } - break; - case DW_TAG_constant: - { - struct psymbol_allocation_list *list; + } +} - if (pdi->is_external) - list = &objfile->global_psymbols; - else - list = &objfile->static_psymbols; - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, VAR_DOMAIN, LOC_STATIC, - list, 0, 0, cu->language, objfile); - } - break; - case DW_TAG_variable: - if (pdi->locdesc) - addr = decode_locdesc (pdi->locdesc, cu); +/* Build the partial symbol table by doing a quick pass through the + .debug_info and .debug_abbrev sections. */ - if (pdi->locdesc - && addr == 0 - && !dwarf2_per_objfile->has_section_at_zero) - { - /* A global or static variable may also have been stripped - out by the linker if unused, in which case its address - will be nullified; do not add such variables into partial - symbol table then. */ - } - else if (pdi->is_external) - { - /* Global Variable. - Don't enter into the minimal symbol tables as there is - a minimal symbol table entry from the ELF symbols already. - Enter into partial symbol table if it has a location - descriptor or a type. - If the location descriptor is missing, new_symbol will create - a LOC_UNRESOLVED symbol, the address of the variable will then - be determined from the minimal symbol table whenever the variable - is referenced. - The address for the partial symbol table entry is not - used by GDB, but it comes in handy for debugging partial symbol - table building. */ +static void +dwarf2_build_psymtabs_hard (struct objfile *objfile) +{ + struct cleanup *back_to, *addrmap_cleanup; + struct obstack temp_obstack; + int i; - if (pdi->locdesc || pdi->has_type) - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, - VAR_DOMAIN, LOC_STATIC, - &objfile->global_psymbols, - 0, addr + baseaddr, - cu->language, objfile); - } - else - { - /* Static Variable. Skip symbols without location descriptors. */ - if (pdi->locdesc == NULL) - { - if (built_actual_name) - xfree (actual_name); - return; - } - /* prim_record_minimal_symbol (actual_name, addr + baseaddr, - mst_file_data, objfile); */ - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, - VAR_DOMAIN, LOC_STATIC, - &objfile->static_psymbols, - 0, addr + baseaddr, - cu->language, objfile); - } - break; - case DW_TAG_typedef: - case DW_TAG_base_type: - case DW_TAG_subrange_type: - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, - VAR_DOMAIN, LOC_TYPEDEF, - &objfile->static_psymbols, - 0, (CORE_ADDR) 0, cu->language, objfile); - break; - case DW_TAG_namespace: - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, - VAR_DOMAIN, LOC_TYPEDEF, - &objfile->global_psymbols, - 0, (CORE_ADDR) 0, cu->language, objfile); - break; - case DW_TAG_class_type: - case DW_TAG_interface_type: - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_enumeration_type: - /* Skip external references. The DWARF standard says in the section - about "Structure, Union, and Class Type Entries": "An incomplete - structure, union or class type is represented by a structure, - union or class entry that does not have a byte size attribute - and that has a DW_AT_declaration attribute." */ - if (!pdi->has_byte_size && pdi->is_declaration) - { - if (built_actual_name) - xfree (actual_name); - return; - } + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "Building psymtabs of objfile %s ...\n", + objfile->name); + } - /* NOTE: carlton/2003-10-07: See comment in new_symbol about - static vs. global. */ - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, - STRUCT_DOMAIN, LOC_TYPEDEF, - (cu->language == language_cplus - || cu->language == language_java) - ? &objfile->global_psymbols - : &objfile->static_psymbols, - 0, (CORE_ADDR) 0, cu->language, objfile); + dwarf2_per_objfile->reading_partial_symbols = 1; - break; - case DW_TAG_enumerator: - add_psymbol_to_list (actual_name, strlen (actual_name), - built_actual_name, - VAR_DOMAIN, LOC_CONST, - (cu->language == language_cplus - || cu->language == language_java) - ? &objfile->global_psymbols - : &objfile->static_psymbols, - 0, (CORE_ADDR) 0, cu->language, objfile); - break; - default: - break; - } + dwarf2_read_section (objfile, &dwarf2_per_objfile->info); - if (built_actual_name) - xfree (actual_name); -} + /* Any cached compilation units will be linked by the per-objfile + read_in_chain. Make sure to free them when we're done. */ + back_to = make_cleanup (free_cached_comp_units, NULL); -/* Read a partial die corresponding to a namespace; also, add a symbol - corresponding to that namespace to the symbol table. NAMESPACE is - the name of the enclosing namespace. */ + build_type_psymtabs (objfile); -static void -add_partial_namespace (struct partial_die_info *pdi, - CORE_ADDR *lowpc, CORE_ADDR *highpc, - int need_pc, struct dwarf2_cu *cu) -{ - /* Add a symbol for the namespace. */ + create_all_comp_units (objfile); - add_partial_symbol (pdi, cu); + /* Create a temporary address map on a temporary obstack. We later + copy this to the final obstack. */ + obstack_init (&temp_obstack); + make_cleanup_obstack_free (&temp_obstack); + objfile->psymtabs_addrmap = addrmap_create_mutable (&temp_obstack); + addrmap_cleanup = make_cleanup (psymtabs_addrmap_cleanup, objfile); - /* Now scan partial symbols in that namespace. */ + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); - if (pdi->has_children) - scan_partial_symbols (pdi->die_child, lowpc, highpc, need_pc, cu); + process_psymtab_comp_unit (per_cu, 0); + } + + set_partial_user (objfile); + + objfile->psymtabs_addrmap = addrmap_create_fixed (objfile->psymtabs_addrmap, + &objfile->objfile_obstack); + discard_cleanups (addrmap_cleanup); + + do_cleanups (back_to); + + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "Done building psymtabs of %s\n", + objfile->name); } -/* Read a partial die corresponding to a Fortran module. */ +/* die_reader_func for load_partial_comp_unit. */ static void -add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc, - CORE_ADDR *highpc, int need_pc, struct dwarf2_cu *cu) +load_partial_comp_unit_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data) { - /* Now scan partial symbols in that module. */ + struct dwarf2_cu *cu = reader->cu; - if (pdi->has_children) - scan_partial_symbols (pdi->die_child, lowpc, highpc, need_pc, cu); + prepare_one_comp_unit (cu, comp_unit_die, language_minimal); + + /* 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 (has_children) + load_partial_dies (reader, info_ptr, 0); } -/* Read a partial die corresponding to a subprogram and create a partial - symbol for that subprogram. When the CU language allows it, this - routine also defines a partial symbol for each nested subprogram - that this subprogram contains. +/* Load the partial DIEs for a secondary CU into memory. + This is also used when rereading a primary CU with load_all_dies. */ - DIE my also be a lexical block, in which case we simply search - recursively for suprograms defined inside that lexical block. - Again, this is only performed when the CU language allows this - type of definitions. */ +static void +load_partial_comp_unit (struct dwarf2_per_cu_data *this_cu) +{ + init_cutu_and_read_dies (this_cu, NULL, 1, 1, + load_partial_comp_unit_reader, NULL); +} static void -add_partial_subprogram (struct partial_die_info *pdi, - CORE_ADDR *lowpc, CORE_ADDR *highpc, - int need_pc, struct dwarf2_cu *cu) +read_comp_units_from_section (struct objfile *objfile, + struct dwarf2_section_info *section, + unsigned int is_dwz, + int *n_allocated, + int *n_comp_units, + struct dwarf2_per_cu_data ***all_comp_units) { - if (pdi->tag == DW_TAG_subprogram) - { - if (pdi->has_pc_info) - { - if (pdi->lowpc < *lowpc) - *lowpc = pdi->lowpc; - if (pdi->highpc > *highpc) - *highpc = pdi->highpc; - if (need_pc) - { - CORE_ADDR baseaddr; - struct objfile *objfile = cu->objfile; + gdb_byte *info_ptr; + bfd *abfd = section->asection->owner; - baseaddr = ANOFFSET (objfile->section_offsets, - SECT_OFF_TEXT (objfile)); - addrmap_set_empty (objfile->psymtabs_addrmap, - pdi->lowpc + baseaddr, - pdi->highpc - 1 + baseaddr, - cu->per_cu->v.psymtab); - } - if (!pdi->is_declaration) - /* Ignore subprogram DIEs that do not have a name, they are - illegal. Do not emit a complaint at this point, we will - do so when we convert this psymtab into a symtab. */ - if (pdi->name) - add_partial_symbol (pdi, cu); - } - } + dwarf2_read_section (objfile, section); - if (! pdi->has_children) - return; + info_ptr = section->buffer; - if (cu->language == language_ada) + while (info_ptr < section->buffer + section->size) { - pdi = pdi->die_child; - while (pdi != NULL) + unsigned int length, initial_length_size; + struct dwarf2_per_cu_data *this_cu; + sect_offset offset; + + offset.sect_off = info_ptr - section->buffer; + + /* Read just enough information to find out where the next + compilation unit is. */ + length = read_initial_length (abfd, info_ptr, &initial_length_size); + + /* Save the compilation unit for later lookup. */ + this_cu = obstack_alloc (&objfile->objfile_obstack, + sizeof (struct dwarf2_per_cu_data)); + memset (this_cu, 0, sizeof (*this_cu)); + this_cu->offset = offset; + this_cu->length = length + initial_length_size; + this_cu->is_dwz = is_dwz; + this_cu->objfile = objfile; + this_cu->info_or_types_section = section; + + if (*n_comp_units == *n_allocated) { - fixup_partial_die (pdi, cu); - if (pdi->tag == DW_TAG_subprogram - || pdi->tag == DW_TAG_lexical_block) - add_partial_subprogram (pdi, lowpc, highpc, need_pc, cu); - pdi = pdi->die_sibling; + *n_allocated *= 2; + *all_comp_units = xrealloc (*all_comp_units, + *n_allocated + * sizeof (struct dwarf2_per_cu_data *)); } + (*all_comp_units)[*n_comp_units] = this_cu; + ++*n_comp_units; + + info_ptr = info_ptr + this_cu->length; } } -/* Read a partial die corresponding to an enumeration type. */ +/* Create a list of all compilation units in OBJFILE. + This is only done for -readnow and building partial symtabs. */ static void -add_partial_enumeration (struct partial_die_info *enum_pdi, - struct dwarf2_cu *cu) +create_all_comp_units (struct objfile *objfile) { - struct partial_die_info *pdi; - - if (enum_pdi->name != NULL) - add_partial_symbol (enum_pdi, cu); + int n_allocated; + int n_comp_units; + struct dwarf2_per_cu_data **all_comp_units; - pdi = enum_pdi->die_child; - while (pdi) + n_comp_units = 0; + n_allocated = 10; + all_comp_units = xmalloc (n_allocated + * sizeof (struct dwarf2_per_cu_data *)); + + read_comp_units_from_section (objfile, &dwarf2_per_objfile->info, 0, + &n_allocated, &n_comp_units, &all_comp_units); + + if (bfd_get_section_by_name (objfile->obfd, ".gnu_debugaltlink") != NULL) { - if (pdi->tag != DW_TAG_enumerator || pdi->name == NULL) - complaint (&symfile_complaints, _("malformed enumerator DIE ignored")); - else - add_partial_symbol (pdi, cu); - pdi = pdi->die_sibling; + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + read_comp_units_from_section (objfile, &dwz->info, 1, + &n_allocated, &n_comp_units, + &all_comp_units); } + + dwarf2_per_objfile->all_comp_units + = obstack_alloc (&objfile->objfile_obstack, + n_comp_units * sizeof (struct dwarf2_per_cu_data *)); + memcpy (dwarf2_per_objfile->all_comp_units, all_comp_units, + n_comp_units * sizeof (struct dwarf2_per_cu_data *)); + xfree (all_comp_units); + dwarf2_per_objfile->n_comp_units = n_comp_units; } -/* Return the initial uleb128 in the die at INFO_PTR. */ +/* Process all loaded DIEs for compilation unit CU, starting at + FIRST_DIE. The caller should pass NEED_PC == 1 if the compilation + unit DIE did not have PC info (DW_AT_low_pc and DW_AT_high_pc, or + DW_AT_ranges). If NEED_PC is set, then this function will set + *LOWPC and *HIGHPC to the lowest and highest PC values found in CU + and record the covered ranges in the addrmap. */ -static unsigned int -peek_abbrev_code (bfd *abfd, gdb_byte *info_ptr) +static void +scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc, + CORE_ADDR *highpc, int need_pc, struct dwarf2_cu *cu) { - unsigned int bytes_read; + struct partial_die_info *pdi; - return read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + /* Now, march along the PDI's, descending into ones which have + interesting children but skipping the children of the other ones, + until we reach the end of the compilation unit. */ + + pdi = first_die; + + while (pdi != NULL) + { + fixup_partial_die (pdi, cu); + + /* Anonymous namespaces or modules have no name but have interesting + children, so we need to look at them. Ditto for anonymous + enums. */ + + if (pdi->name != NULL || pdi->tag == DW_TAG_namespace + || pdi->tag == DW_TAG_module || pdi->tag == DW_TAG_enumeration_type + || pdi->tag == DW_TAG_imported_unit) + { + switch (pdi->tag) + { + case DW_TAG_subprogram: + add_partial_subprogram (pdi, lowpc, highpc, need_pc, cu); + break; + case DW_TAG_constant: + case DW_TAG_variable: + case DW_TAG_typedef: + case DW_TAG_union_type: + if (!pdi->is_declaration) + { + add_partial_symbol (pdi, cu); + } + break; + case DW_TAG_class_type: + case DW_TAG_interface_type: + case DW_TAG_structure_type: + if (!pdi->is_declaration) + { + add_partial_symbol (pdi, cu); + } + break; + case DW_TAG_enumeration_type: + if (!pdi->is_declaration) + add_partial_enumeration (pdi, cu); + break; + case DW_TAG_base_type: + case DW_TAG_subrange_type: + /* File scope base type definitions are added to the partial + symbol table. */ + add_partial_symbol (pdi, cu); + break; + case DW_TAG_namespace: + add_partial_namespace (pdi, lowpc, highpc, need_pc, cu); + break; + case DW_TAG_module: + add_partial_module (pdi, lowpc, highpc, need_pc, cu); + break; + case DW_TAG_imported_unit: + { + struct dwarf2_per_cu_data *per_cu; + + /* For now we don't handle imported units in type units. */ + if (cu->per_cu->is_debug_types) + { + error (_("Dwarf Error: DW_TAG_imported_unit is not" + " supported in type units [in module %s]"), + cu->objfile->name); + } + + per_cu = dwarf2_find_containing_comp_unit (pdi->d.offset, + pdi->is_dwz, + cu->objfile); + + /* Go read the partial unit, if needed. */ + if (per_cu->v.psymtab == NULL) + process_psymtab_comp_unit (per_cu, 1); + + VEC_safe_push (dwarf2_per_cu_ptr, + cu->per_cu->imported_symtabs, per_cu); + } + break; + default: + break; + } + } + + /* If the die has a sibling, skip to the sibling. */ + + pdi = pdi->die_sibling; + } } -/* Read the initial uleb128 in the die at INFO_PTR in compilation unit CU. - Return the corresponding abbrev, or NULL if the number is zero (indicating - an empty DIE). In either case *BYTES_READ will be set to the length of - the initial number. */ +/* Functions used to compute the fully scoped name of a partial DIE. -static struct abbrev_info * -peek_die_abbrev (gdb_byte *info_ptr, unsigned int *bytes_read, - struct dwarf2_cu *cu) + Normally, this is simple. For C++, the parent DIE's fully scoped + name is concatenated with "::" and the partial DIE's name. For + Java, the same thing occurs except that "." is used instead of "::". + Enumerators are an exception; they use the scope of their parent + enumeration type, i.e. the name of the enumeration type is not + prepended to the enumerator. + + There are two complexities. One is DW_AT_specification; in this + case "parent" means the parent of the target of the specification, + instead of the direct parent of the DIE. The other is compilers + which do not emit DW_TAG_namespace; in this case we try to guess + the fully qualified name of structure types from their members' + linkage names. This must be done using the DIE's children rather + than the children of any DW_AT_specification target. We only need + to do this for structures at the top level, i.e. if the target of + any DW_AT_specification (if any; otherwise the DIE itself) does not + have a parent. */ + +/* Compute the scope prefix associated with PDI's parent, in + compilation unit CU. The result will be allocated on CU's + comp_unit_obstack, or a copy of the already allocated PDI->NAME + field. NULL is returned if no prefix is necessary. */ +static const char * +partial_die_parent_scope (struct partial_die_info *pdi, + struct dwarf2_cu *cu) { - bfd *abfd = cu->objfile->obfd; - unsigned int abbrev_number; - struct abbrev_info *abbrev; + const char *grandparent_scope; + struct partial_die_info *parent, *real_pdi; - abbrev_number = read_unsigned_leb128 (abfd, info_ptr, bytes_read); + /* We need to look at our parent DIE; if we have a DW_AT_specification, + then this means the parent of the specification DIE. */ - if (abbrev_number == 0) + real_pdi = pdi; + while (real_pdi->has_specification) + real_pdi = find_partial_die (real_pdi->spec_offset, + real_pdi->spec_is_dwz, cu); + + parent = real_pdi->die_parent; + if (parent == NULL) return NULL; - abbrev = dwarf2_lookup_abbrev (abbrev_number, cu); - if (!abbrev) - { - error (_("Dwarf Error: Could not find abbrev number %d [in module %s]"), - abbrev_number, bfd_get_filename (abfd)); - } + if (parent->scope_set) + return parent->scope; - return abbrev; -} + fixup_partial_die (parent, cu); -/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER. - Returns a pointer to the end of a series of DIEs, terminated by an empty - DIE. Any children of the skipped DIEs will also be skipped. */ + grandparent_scope = partial_die_parent_scope (parent, cu); -static gdb_byte * -skip_children (gdb_byte *buffer, gdb_byte *info_ptr, struct dwarf2_cu *cu) -{ - struct abbrev_info *abbrev; - unsigned int bytes_read; + /* GCC 4.0 and 4.1 had a bug (PR c++/28460) where they generated bogus + DW_TAG_namespace DIEs with a name of "::" for the global namespace. + Work around this problem here. */ + if (cu->language == language_cplus + && parent->tag == DW_TAG_namespace + && strcmp (parent->name, "::") == 0 + && grandparent_scope == NULL) + { + parent->scope = NULL; + parent->scope_set = 1; + return NULL; + } - while (1) + if (pdi->tag == DW_TAG_enumerator) + /* Enumerators should not get the name of the enumeration as a prefix. */ + parent->scope = grandparent_scope; + else if (parent->tag == DW_TAG_namespace + || parent->tag == DW_TAG_module + || parent->tag == DW_TAG_structure_type + || parent->tag == DW_TAG_class_type + || parent->tag == DW_TAG_interface_type + || parent->tag == DW_TAG_union_type + || parent->tag == DW_TAG_enumeration_type) { - abbrev = peek_die_abbrev (info_ptr, &bytes_read, cu); - if (abbrev == NULL) - return info_ptr + bytes_read; + if (grandparent_scope == NULL) + parent->scope = parent->name; else - info_ptr = skip_one_die (buffer, info_ptr + bytes_read, abbrev, cu); + parent->scope = typename_concat (&cu->comp_unit_obstack, + grandparent_scope, + parent->name, 0, cu); + } + else + { + /* FIXME drow/2004-04-01: What should we be doing with + function-local names? For partial symbols, we should probably be + ignoring them. */ + complaint (&symfile_complaints, + _("unhandled containing DIE tag %d for DIE at %d"), + parent->tag, pdi->offset.sect_off); + parent->scope = grandparent_scope; } + + parent->scope_set = 1; + return parent->scope; } -/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER. - INFO_PTR should point just after the initial uleb128 of a DIE, and the - abbrev corresponding to that skipped uleb128 should be passed in - ABBREV. Returns a pointer to this DIE's sibling, skipping any - children. */ +/* Return the fully scoped name associated with PDI, from compilation unit + CU. The result will be allocated with malloc. */ -static gdb_byte * -skip_one_die (gdb_byte *buffer, gdb_byte *info_ptr, - struct abbrev_info *abbrev, struct dwarf2_cu *cu) +static char * +partial_die_full_name (struct partial_die_info *pdi, + struct dwarf2_cu *cu) { - unsigned int bytes_read; - struct attribute attr; - bfd *abfd = cu->objfile->obfd; - unsigned int form, i; + const char *parent_scope; - for (i = 0; i < abbrev->num_attrs; i++) + /* If this is a template instantiation, we can not work out the + template arguments from partial DIEs. So, unfortunately, we have + to go through the full DIEs. At least any work we do building + types here will be reused if full symbols are loaded later. */ + if (pdi->has_template_arguments) { - /* The only abbrev we care about is DW_AT_sibling. */ - if (abbrev->attrs[i].name == DW_AT_sibling) - { - read_attribute (&attr, &abbrev->attrs[i], - abfd, info_ptr, cu); - if (attr.form == DW_FORM_ref_addr) - complaint (&symfile_complaints, - _("ignoring absolute DW_AT_sibling")); - else - return buffer + dwarf2_get_ref_die_offset (&attr); - } + fixup_partial_die (pdi, cu); - /* If it isn't DW_AT_sibling, skip this attribute. */ - form = abbrev->attrs[i].form; - skip_attribute: - switch (form) + if (pdi->name != NULL && strchr (pdi->name, '<') == NULL) + { + struct die_info *die; + struct attribute attr; + struct dwarf2_cu *ref_cu = cu; + + /* DW_FORM_ref_addr is using section offset. */ + attr.name = 0; + attr.form = DW_FORM_ref_addr; + attr.u.unsnd = pdi->offset.sect_off; + die = follow_die_ref (NULL, &attr, &ref_cu); + + return xstrdup (dwarf2_full_name (NULL, die, ref_cu)); + } + } + + parent_scope = partial_die_parent_scope (pdi, cu); + if (parent_scope == NULL) + return NULL; + else + return typename_concat (NULL, parent_scope, pdi->name, 0, cu); +} + +static void +add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) +{ + struct objfile *objfile = cu->objfile; + CORE_ADDR addr = 0; + const char *actual_name = NULL; + CORE_ADDR baseaddr; + char *built_actual_name; + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + built_actual_name = partial_die_full_name (pdi, cu); + if (built_actual_name != NULL) + actual_name = built_actual_name; + + if (actual_name == NULL) + actual_name = pdi->name; + + switch (pdi->tag) + { + case DW_TAG_subprogram: + if (pdi->is_external || cu->language == language_ada) + { + /* brobecker/2007-12-26: Normally, only "external" DIEs are part + of the global scope. But in Ada, we want to be able to access + nested procedures globally. So all Ada subprograms are stored + in the global scope. */ + /* prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr, + mst_text, objfile); */ + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, + VAR_DOMAIN, LOC_BLOCK, + &objfile->global_psymbols, + 0, pdi->lowpc + baseaddr, + cu->language, objfile); + } + else + { + /* prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr, + mst_file_text, objfile); */ + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, + VAR_DOMAIN, LOC_BLOCK, + &objfile->static_psymbols, + 0, pdi->lowpc + baseaddr, + cu->language, objfile); + } + break; + case DW_TAG_constant: + { + struct psymbol_allocation_list *list; + + if (pdi->is_external) + list = &objfile->global_psymbols; + else + list = &objfile->static_psymbols; + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, VAR_DOMAIN, LOC_STATIC, + list, 0, 0, cu->language, objfile); + } + break; + case DW_TAG_variable: + if (pdi->d.locdesc) + addr = decode_locdesc (pdi->d.locdesc, cu); + + if (pdi->d.locdesc + && addr == 0 + && !dwarf2_per_objfile->has_section_at_zero) + { + /* A global or static variable may also have been stripped + out by the linker if unused, in which case its address + will be nullified; do not add such variables into partial + symbol table then. */ + } + else if (pdi->is_external) + { + /* Global Variable. + Don't enter into the minimal symbol tables as there is + a minimal symbol table entry from the ELF symbols already. + Enter into partial symbol table if it has a location + descriptor or a type. + If the location descriptor is missing, new_symbol will create + a LOC_UNRESOLVED symbol, the address of the variable will then + be determined from the minimal symbol table whenever the variable + is referenced. + The address for the partial symbol table entry is not + used by GDB, but it comes in handy for debugging partial symbol + table building. */ + + if (pdi->d.locdesc || pdi->has_type) + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, + VAR_DOMAIN, LOC_STATIC, + &objfile->global_psymbols, + 0, addr + baseaddr, + cu->language, objfile); + } + else + { + /* Static Variable. Skip symbols without location descriptors. */ + if (pdi->d.locdesc == NULL) + { + xfree (built_actual_name); + return; + } + /* prim_record_minimal_symbol (actual_name, addr + baseaddr, + mst_file_data, objfile); */ + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, + VAR_DOMAIN, LOC_STATIC, + &objfile->static_psymbols, + 0, addr + baseaddr, + cu->language, objfile); + } + break; + case DW_TAG_typedef: + case DW_TAG_base_type: + case DW_TAG_subrange_type: + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, + VAR_DOMAIN, LOC_TYPEDEF, + &objfile->static_psymbols, + 0, (CORE_ADDR) 0, cu->language, objfile); + break; + case DW_TAG_namespace: + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, + VAR_DOMAIN, LOC_TYPEDEF, + &objfile->global_psymbols, + 0, (CORE_ADDR) 0, cu->language, objfile); + break; + case DW_TAG_class_type: + case DW_TAG_interface_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_enumeration_type: + /* Skip external references. The DWARF standard says in the section + about "Structure, Union, and Class Type Entries": "An incomplete + structure, union or class type is represented by a structure, + union or class entry that does not have a byte size attribute + and that has a DW_AT_declaration attribute." */ + if (!pdi->has_byte_size && pdi->is_declaration) + { + xfree (built_actual_name); + return; + } + + /* NOTE: carlton/2003-10-07: See comment in new_symbol about + static vs. global. */ + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, + STRUCT_DOMAIN, LOC_TYPEDEF, + (cu->language == language_cplus + || cu->language == language_java) + ? &objfile->global_psymbols + : &objfile->static_psymbols, + 0, (CORE_ADDR) 0, cu->language, objfile); + + break; + case DW_TAG_enumerator: + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, + VAR_DOMAIN, LOC_CONST, + (cu->language == language_cplus + || cu->language == language_java) + ? &objfile->global_psymbols + : &objfile->static_psymbols, + 0, (CORE_ADDR) 0, cu->language, objfile); + break; + default: + break; + } + + xfree (built_actual_name); +} + +/* Read a partial die corresponding to a namespace; also, add a symbol + corresponding to that namespace to the symbol table. NAMESPACE is + the name of the enclosing namespace. */ + +static void +add_partial_namespace (struct partial_die_info *pdi, + CORE_ADDR *lowpc, CORE_ADDR *highpc, + int need_pc, struct dwarf2_cu *cu) +{ + /* Add a symbol for the namespace. */ + + add_partial_symbol (pdi, cu); + + /* Now scan partial symbols in that namespace. */ + + if (pdi->has_children) + scan_partial_symbols (pdi->die_child, lowpc, highpc, need_pc, cu); +} + +/* Read a partial die corresponding to a Fortran module. */ + +static void +add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc, + CORE_ADDR *highpc, int need_pc, struct dwarf2_cu *cu) +{ + /* Now scan partial symbols in that module. */ + + if (pdi->has_children) + scan_partial_symbols (pdi->die_child, lowpc, highpc, need_pc, cu); +} + +/* Read a partial die corresponding to a subprogram and create a partial + symbol for that subprogram. When the CU language allows it, this + routine also defines a partial symbol for each nested subprogram + that this subprogram contains. + + DIE my also be a lexical block, in which case we simply search + recursively for suprograms defined inside that lexical block. + Again, this is only performed when the CU language allows this + type of definitions. */ + +static void +add_partial_subprogram (struct partial_die_info *pdi, + CORE_ADDR *lowpc, CORE_ADDR *highpc, + int need_pc, struct dwarf2_cu *cu) +{ + if (pdi->tag == DW_TAG_subprogram) + { + if (pdi->has_pc_info) + { + if (pdi->lowpc < *lowpc) + *lowpc = pdi->lowpc; + if (pdi->highpc > *highpc) + *highpc = pdi->highpc; + if (need_pc) + { + CORE_ADDR baseaddr; + struct objfile *objfile = cu->objfile; + + baseaddr = ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT (objfile)); + addrmap_set_empty (objfile->psymtabs_addrmap, + pdi->lowpc + baseaddr, + pdi->highpc - 1 + baseaddr, + cu->per_cu->v.psymtab); + } + } + + if (pdi->has_pc_info || (!pdi->is_external && pdi->may_be_inlined)) + { + if (!pdi->is_declaration) + /* Ignore subprogram DIEs that do not have a name, they are + illegal. Do not emit a complaint at this point, we will + do so when we convert this psymtab into a symtab. */ + if (pdi->name) + add_partial_symbol (pdi, cu); + } + } + + if (! pdi->has_children) + return; + + if (cu->language == language_ada) + { + pdi = pdi->die_child; + while (pdi != NULL) + { + fixup_partial_die (pdi, cu); + if (pdi->tag == DW_TAG_subprogram + || pdi->tag == DW_TAG_lexical_block) + add_partial_subprogram (pdi, lowpc, highpc, need_pc, cu); + pdi = pdi->die_sibling; + } + } +} + +/* Read a partial die corresponding to an enumeration type. */ + +static void +add_partial_enumeration (struct partial_die_info *enum_pdi, + struct dwarf2_cu *cu) +{ + struct partial_die_info *pdi; + + if (enum_pdi->name != NULL) + add_partial_symbol (enum_pdi, cu); + + pdi = enum_pdi->die_child; + while (pdi) + { + if (pdi->tag != DW_TAG_enumerator || pdi->name == NULL) + complaint (&symfile_complaints, _("malformed enumerator DIE ignored")); + else + add_partial_symbol (pdi, cu); + pdi = pdi->die_sibling; + } +} + +/* Return the initial uleb128 in the die at INFO_PTR. */ + +static unsigned int +peek_abbrev_code (bfd *abfd, gdb_byte *info_ptr) +{ + unsigned int bytes_read; + + return read_unsigned_leb128 (abfd, info_ptr, &bytes_read); +} + +/* Read the initial uleb128 in the die at INFO_PTR in compilation unit CU. + Return the corresponding abbrev, or NULL if the number is zero (indicating + an empty DIE). In either case *BYTES_READ will be set to the length of + the initial number. */ + +static struct abbrev_info * +peek_die_abbrev (gdb_byte *info_ptr, unsigned int *bytes_read, + struct dwarf2_cu *cu) +{ + bfd *abfd = cu->objfile->obfd; + unsigned int abbrev_number; + struct abbrev_info *abbrev; + + abbrev_number = read_unsigned_leb128 (abfd, info_ptr, bytes_read); + + if (abbrev_number == 0) + return NULL; + + abbrev = abbrev_table_lookup_abbrev (cu->abbrev_table, abbrev_number); + if (!abbrev) + { + error (_("Dwarf Error: Could not find abbrev number %d [in module %s]"), + abbrev_number, bfd_get_filename (abfd)); + } + + return abbrev; +} + +/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER. + Returns a pointer to the end of a series of DIEs, terminated by an empty + DIE. Any children of the skipped DIEs will also be skipped. */ + +static gdb_byte * +skip_children (const struct die_reader_specs *reader, gdb_byte *info_ptr) +{ + struct dwarf2_cu *cu = reader->cu; + struct abbrev_info *abbrev; + unsigned int bytes_read; + + while (1) + { + abbrev = peek_die_abbrev (info_ptr, &bytes_read, cu); + if (abbrev == NULL) + return info_ptr + bytes_read; + else + info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev); + } +} + +/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER. + INFO_PTR should point just after the initial uleb128 of a DIE, and the + abbrev corresponding to that skipped uleb128 should be passed in + ABBREV. Returns a pointer to this DIE's sibling, skipping any + children. */ + +static gdb_byte * +skip_one_die (const struct die_reader_specs *reader, gdb_byte *info_ptr, + struct abbrev_info *abbrev) +{ + unsigned int bytes_read; + struct attribute attr; + bfd *abfd = reader->abfd; + struct dwarf2_cu *cu = reader->cu; + gdb_byte *buffer = reader->buffer; + const gdb_byte *buffer_end = reader->buffer_end; + gdb_byte *start_info_ptr = info_ptr; + unsigned int form, i; + + for (i = 0; i < abbrev->num_attrs; i++) + { + /* The only abbrev we care about is DW_AT_sibling. */ + if (abbrev->attrs[i].name == DW_AT_sibling) + { + read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr); + if (attr.form == DW_FORM_ref_addr) + complaint (&symfile_complaints, + _("ignoring absolute DW_AT_sibling")); + else + return buffer + dwarf2_get_ref_die_offset (&attr).sect_off; + } + + /* If it isn't DW_AT_sibling, skip this attribute. */ + form = abbrev->attrs[i].form; + skip_attribute: + switch (form) { case DW_FORM_ref_addr: /* In DWARF 2, DW_FORM_ref_addr is address sized; in DWARF 3 @@ -4449,1432 +6306,2988 @@ skip_one_die (gdb_byte *buffer, gdb_byte *info_ptr, if (cu->header.version == 2) info_ptr += cu->header.addr_size; else - info_ptr += cu->header.offset_size; - break; - case DW_FORM_addr: - info_ptr += cu->header.addr_size; - break; - case DW_FORM_data1: - case DW_FORM_ref1: - case DW_FORM_flag: - info_ptr += 1; - break; - case DW_FORM_flag_present: - break; - case DW_FORM_data2: - case DW_FORM_ref2: - info_ptr += 2; - break; - case DW_FORM_data4: - case DW_FORM_ref4: - info_ptr += 4; - break; - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - info_ptr += 8; - break; - case DW_FORM_string: - read_direct_string (abfd, info_ptr, &bytes_read); - info_ptr += bytes_read; - break; - case DW_FORM_sec_offset: - case DW_FORM_strp: - info_ptr += cu->header.offset_size; - break; - case DW_FORM_exprloc: - case DW_FORM_block: - info_ptr += read_unsigned_leb128 (abfd, info_ptr, &bytes_read); - info_ptr += bytes_read; - break; - case DW_FORM_block1: - info_ptr += 1 + read_1_byte (abfd, info_ptr); - break; - case DW_FORM_block2: - info_ptr += 2 + read_2_bytes (abfd, info_ptr); - break; - case DW_FORM_block4: - info_ptr += 4 + read_4_bytes (abfd, info_ptr); - break; - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - info_ptr = skip_leb128 (abfd, info_ptr); - break; - case DW_FORM_indirect: - form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); - info_ptr += bytes_read; - /* We need to continue parsing from here, so just go back to - the top. */ - goto skip_attribute; + info_ptr += cu->header.offset_size; + break; + case DW_FORM_GNU_ref_alt: + info_ptr += cu->header.offset_size; + break; + case DW_FORM_addr: + info_ptr += cu->header.addr_size; + break; + case DW_FORM_data1: + case DW_FORM_ref1: + case DW_FORM_flag: + info_ptr += 1; + break; + case DW_FORM_flag_present: + break; + case DW_FORM_data2: + case DW_FORM_ref2: + info_ptr += 2; + break; + case DW_FORM_data4: + case DW_FORM_ref4: + info_ptr += 4; + break; + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + info_ptr += 8; + break; + case DW_FORM_string: + read_direct_string (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_sec_offset: + case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: + info_ptr += cu->header.offset_size; + break; + case DW_FORM_exprloc: + case DW_FORM_block: + info_ptr += read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_block1: + info_ptr += 1 + read_1_byte (abfd, info_ptr); + break; + case DW_FORM_block2: + info_ptr += 2 + read_2_bytes (abfd, info_ptr); + break; + case DW_FORM_block4: + info_ptr += 4 + read_4_bytes (abfd, info_ptr); + break; + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + info_ptr = (gdb_byte *) safe_skip_leb128 (info_ptr, buffer_end); + break; + case DW_FORM_indirect: + form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + /* We need to continue parsing from here, so just go back to + the top. */ + goto skip_attribute; + + default: + error (_("Dwarf Error: Cannot handle %s " + "in DWARF reader [in module %s]"), + dwarf_form_name (form), + bfd_get_filename (abfd)); + } + } + + if (abbrev->has_children) + return skip_children (reader, info_ptr); + else + return info_ptr; +} + +/* Locate ORIG_PDI's sibling. + INFO_PTR should point to the start of the next DIE after ORIG_PDI. */ + +static gdb_byte * +locate_pdi_sibling (const struct die_reader_specs *reader, + struct partial_die_info *orig_pdi, + gdb_byte *info_ptr) +{ + /* Do we know the sibling already? */ + + if (orig_pdi->sibling) + return orig_pdi->sibling; + + /* Are there any children to deal with? */ + + if (!orig_pdi->has_children) + return info_ptr; + + /* Skip the children the long way. */ + + return skip_children (reader, info_ptr); +} + +/* Expand this partial symbol table into a full symbol table. SELF is + not NULL. */ + +static void +dwarf2_read_symtab (struct partial_symtab *self, + struct objfile *objfile) +{ + if (self->readin) + { + warning (_("bug: psymtab for %s is already read in."), + self->filename); + } + else + { + if (info_verbose) + { + printf_filtered (_("Reading in symbols for %s..."), + self->filename); + gdb_flush (gdb_stdout); + } + + /* Restore our global data. */ + dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); + + /* If this psymtab is constructed from a debug-only objfile, the + has_section_at_zero flag will not necessarily be correct. We + can get the correct value for this flag by looking at the data + associated with the (presumably stripped) associated objfile. */ + if (objfile->separate_debug_objfile_backlink) + { + struct dwarf2_per_objfile *dpo_backlink + = objfile_data (objfile->separate_debug_objfile_backlink, + dwarf2_objfile_data_key); + + dwarf2_per_objfile->has_section_at_zero + = dpo_backlink->has_section_at_zero; + } + + dwarf2_per_objfile->reading_partial_symbols = 0; + + psymtab_to_symtab_1 (self); + + /* Finish up the debug error message. */ + if (info_verbose) + printf_filtered (_("done.\n")); + } + + process_cu_includes (); +} + +/* Reading in full CUs. */ + +/* Add PER_CU to the queue. */ + +static void +queue_comp_unit (struct dwarf2_per_cu_data *per_cu, + enum language pretend_language) +{ + struct dwarf2_queue_item *item; + + per_cu->queued = 1; + item = xmalloc (sizeof (*item)); + item->per_cu = per_cu; + item->pretend_language = pretend_language; + item->next = NULL; + + if (dwarf2_queue == NULL) + dwarf2_queue = item; + else + dwarf2_queue_tail->next = item; + + dwarf2_queue_tail = item; +} + +/* THIS_CU has a reference to PER_CU. If necessary, load the new compilation + unit and add it to our queue. + The result is non-zero if PER_CU was queued, otherwise the result is zero + meaning either PER_CU is already queued or it is already loaded. */ + +static int +maybe_queue_comp_unit (struct dwarf2_cu *this_cu, + struct dwarf2_per_cu_data *per_cu, + enum language pretend_language) +{ + /* We may arrive here during partial symbol reading, if we need full + DIEs to process an unusual case (e.g. template arguments). Do + not queue PER_CU, just tell our caller to load its DIEs. */ + if (dwarf2_per_objfile->reading_partial_symbols) + { + if (per_cu->cu == NULL || per_cu->cu->dies == NULL) + return 1; + return 0; + } + + /* Mark the dependence relation so that we don't flush PER_CU + too early. */ + dwarf2_add_dependence (this_cu, per_cu); + + /* If it's already on the queue, we have nothing to do. */ + if (per_cu->queued) + return 0; + + /* If the compilation unit is already loaded, just mark it as + used. */ + if (per_cu->cu != NULL) + { + per_cu->cu->last_used = 0; + return 0; + } + + /* Add it to the queue. */ + queue_comp_unit (per_cu, pretend_language); + + return 1; +} + +/* Process the queue. */ + +static void +process_queue (void) +{ + struct dwarf2_queue_item *item, *next_item; + + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Expanding one or more symtabs of objfile %s ...\n", + dwarf2_per_objfile->objfile->name); + } + + /* The queue starts out with one item, but following a DIE reference + may load a new CU, adding it to the end of the queue. */ + for (item = dwarf2_queue; item != NULL; dwarf2_queue = item = next_item) + { + if (dwarf2_per_objfile->using_index + ? !item->per_cu->v.quick->symtab + : (item->per_cu->v.psymtab && !item->per_cu->v.psymtab->readin)) + { + struct dwarf2_per_cu_data *per_cu = item->per_cu; + + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Expanding symtab of %s at offset 0x%x\n", + per_cu->is_debug_types ? "TU" : "CU", + per_cu->offset.sect_off); + } + + if (per_cu->is_debug_types) + process_full_type_unit (per_cu, item->pretend_language); + else + process_full_comp_unit (per_cu, item->pretend_language); + + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Done expanding %s at offset 0x%x\n", + per_cu->is_debug_types ? "TU" : "CU", + per_cu->offset.sect_off); + } + } + + item->per_cu->queued = 0; + next_item = item->next; + xfree (item); + } + + dwarf2_queue_tail = NULL; + + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "Done expanding symtabs of %s.\n", + dwarf2_per_objfile->objfile->name); + } +} + +/* Free all allocated queue entries. This function only releases anything if + an error was thrown; if the queue was processed then it would have been + freed as we went along. */ + +static void +dwarf2_release_queue (void *dummy) +{ + struct dwarf2_queue_item *item, *last; + + item = dwarf2_queue; + while (item) + { + /* Anything still marked queued is likely to be in an + inconsistent state, so discard it. */ + if (item->per_cu->queued) + { + if (item->per_cu->cu != NULL) + free_one_cached_comp_unit (item->per_cu); + item->per_cu->queued = 0; + } + + last = item; + item = item->next; + xfree (last); + } + + dwarf2_queue = dwarf2_queue_tail = NULL; +} + +/* Read in full symbols for PST, and anything it depends on. */ + +static void +psymtab_to_symtab_1 (struct partial_symtab *pst) +{ + struct dwarf2_per_cu_data *per_cu; + int i; + + if (pst->readin) + return; + + for (i = 0; i < pst->number_of_dependencies; i++) + if (!pst->dependencies[i]->readin + && pst->dependencies[i]->user == NULL) + { + /* Inform about additional files that need to be read in. */ + if (info_verbose) + { + /* FIXME: i18n: Need to make this a single string. */ + fputs_filtered (" ", gdb_stdout); + wrap_here (""); + fputs_filtered ("and ", gdb_stdout); + wrap_here (""); + printf_filtered ("%s...", pst->dependencies[i]->filename); + wrap_here (""); /* Flush output. */ + gdb_flush (gdb_stdout); + } + psymtab_to_symtab_1 (pst->dependencies[i]); + } + + per_cu = pst->read_symtab_private; + + if (per_cu == NULL) + { + /* It's an include file, no symbols to read for it. + Everything is in the parent symtab. */ + pst->readin = 1; + return; + } + + dw2_do_instantiate_symtab (per_cu); +} + +/* Trivial hash function for die_info: the hash value of a DIE + is its offset in .debug_info for this objfile. */ + +static hashval_t +die_hash (const void *item) +{ + const struct die_info *die = item; + + return die->offset.sect_off; +} + +/* Trivial comparison function for die_info structures: two DIEs + are equal if they have the same offset. */ + +static int +die_eq (const void *item_lhs, const void *item_rhs) +{ + const struct die_info *die_lhs = item_lhs; + const struct die_info *die_rhs = item_rhs; + + return die_lhs->offset.sect_off == die_rhs->offset.sect_off; +} + +/* die_reader_func for load_full_comp_unit. + This is identical to read_signatured_type_reader, + but is kept separate for now. */ + +static void +load_full_comp_unit_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data) +{ + struct dwarf2_cu *cu = reader->cu; + enum language *language_ptr = data; + + gdb_assert (cu->die_hash == NULL); + cu->die_hash = + htab_create_alloc_ex (cu->header.length / 12, + die_hash, + die_eq, + NULL, + &cu->comp_unit_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); + + if (has_children) + comp_unit_die->child = read_die_and_siblings (reader, info_ptr, + &info_ptr, comp_unit_die); + cu->dies = comp_unit_die; + /* comp_unit_die is not stored in die_hash, no need. */ + + /* We try not to read any attributes in this function, because not + all CUs needed for references have been loaded yet, and symbol + table processing isn't initialized. But we have to set the CU language, + or we won't be able to build types correctly. + Similarly, if we do not read the producer, we can not apply + producer-specific interpretation. */ + prepare_one_comp_unit (cu, cu->dies, *language_ptr); +} + +/* Load the DIEs associated with PER_CU into memory. */ + +static void +load_full_comp_unit (struct dwarf2_per_cu_data *this_cu, + enum language pretend_language) +{ + gdb_assert (! this_cu->is_debug_types); + + init_cutu_and_read_dies (this_cu, NULL, 1, 1, + load_full_comp_unit_reader, &pretend_language); +} + +/* Add a DIE to the delayed physname list. */ + +static void +add_to_method_list (struct type *type, int fnfield_index, int index, + const char *name, struct die_info *die, + struct dwarf2_cu *cu) +{ + struct delayed_method_info mi; + mi.type = type; + mi.fnfield_index = fnfield_index; + mi.index = index; + mi.name = name; + mi.die = die; + VEC_safe_push (delayed_method_info, cu->method_list, &mi); +} + +/* A cleanup for freeing the delayed method list. */ + +static void +free_delayed_list (void *ptr) +{ + struct dwarf2_cu *cu = (struct dwarf2_cu *) ptr; + if (cu->method_list != NULL) + { + VEC_free (delayed_method_info, cu->method_list); + cu->method_list = NULL; + } +} + +/* Compute the physnames of any methods on the CU's method list. + + The computation of method physnames is delayed in order to avoid the + (bad) condition that one of the method's formal parameters is of an as yet + incomplete type. */ + +static void +compute_delayed_physnames (struct dwarf2_cu *cu) +{ + int i; + struct delayed_method_info *mi; + for (i = 0; VEC_iterate (delayed_method_info, cu->method_list, i, mi) ; ++i) + { + const char *physname; + struct fn_fieldlist *fn_flp + = &TYPE_FN_FIELDLIST (mi->type, mi->fnfield_index); + physname = dwarf2_physname (mi->name, mi->die, cu); + fn_flp->fn_fields[mi->index].physname = physname ? physname : ""; + } +} + +/* Go objects should be embedded in a DW_TAG_module DIE, + and it's not clear if/how imported objects will appear. + To keep Go support simple until that's worked out, + go back through what we've read and create something usable. + We could do this while processing each DIE, and feels kinda cleaner, + but that way is more invasive. + This is to, for example, allow the user to type "p var" or "b main" + without having to specify the package name, and allow lookups + of module.object to work in contexts that use the expression + parser. */ + +static void +fixup_go_packaging (struct dwarf2_cu *cu) +{ + char *package_name = NULL; + struct pending *list; + int i; + + for (list = global_symbols; list != NULL; list = list->next) + { + for (i = 0; i < list->nsyms; ++i) + { + struct symbol *sym = list->symbol[i]; + + if (SYMBOL_LANGUAGE (sym) == language_go + && SYMBOL_CLASS (sym) == LOC_BLOCK) + { + char *this_package_name = go_symbol_package_name (sym); + + if (this_package_name == NULL) + continue; + if (package_name == NULL) + package_name = this_package_name; + else + { + if (strcmp (package_name, this_package_name) != 0) + complaint (&symfile_complaints, + _("Symtab %s has objects from two different Go packages: %s and %s"), + (SYMBOL_SYMTAB (sym) + ? symtab_to_filename_for_display (SYMBOL_SYMTAB (sym)) + : cu->objfile->name), + this_package_name, package_name); + xfree (this_package_name); + } + } + } + } + + if (package_name != NULL) + { + struct objfile *objfile = cu->objfile; + const char *saved_package_name = obstack_copy0 (&objfile->objfile_obstack, + package_name, + strlen (package_name)); + struct type *type = init_type (TYPE_CODE_MODULE, 0, 0, + saved_package_name, objfile); + struct symbol *sym; + + TYPE_TAG_NAME (type) = TYPE_NAME (type); + + sym = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol); + SYMBOL_SET_LANGUAGE (sym, language_go); + SYMBOL_SET_NAMES (sym, saved_package_name, + strlen (saved_package_name), 0, objfile); + /* This is not VAR_DOMAIN because we want a way to ensure a lookup of, + e.g., "main" finds the "main" module and not C's main(). */ + SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN; + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_TYPE (sym) = type; + + add_symbol_to_list (sym, &global_symbols); + + xfree (package_name); + } +} + +static void compute_symtab_includes (struct dwarf2_per_cu_data *per_cu); + +/* Return the symtab for PER_CU. This works properly regardless of + whether we're using the index or psymtabs. */ + +static struct symtab * +get_symtab (struct dwarf2_per_cu_data *per_cu) +{ + return (dwarf2_per_objfile->using_index + ? per_cu->v.quick->symtab + : per_cu->v.psymtab->symtab); +} + +/* A helper function for computing the list of all symbol tables + included by PER_CU. */ + +static void +recursively_compute_inclusions (VEC (dwarf2_per_cu_ptr) **result, + htab_t all_children, + struct dwarf2_per_cu_data *per_cu) +{ + void **slot; + int ix; + struct dwarf2_per_cu_data *iter; + + slot = htab_find_slot (all_children, per_cu, INSERT); + if (*slot != NULL) + { + /* This inclusion and its children have been processed. */ + return; + } + + *slot = per_cu; + /* Only add a CU if it has a symbol table. */ + if (get_symtab (per_cu) != NULL) + VEC_safe_push (dwarf2_per_cu_ptr, *result, per_cu); + + for (ix = 0; + VEC_iterate (dwarf2_per_cu_ptr, per_cu->imported_symtabs, ix, iter); + ++ix) + recursively_compute_inclusions (result, all_children, iter); +} + +/* Compute the symtab 'includes' fields for the symtab related to + PER_CU. */ + +static void +compute_symtab_includes (struct dwarf2_per_cu_data *per_cu) +{ + gdb_assert (! per_cu->is_debug_types); + + if (!VEC_empty (dwarf2_per_cu_ptr, per_cu->imported_symtabs)) + { + int ix, len; + struct dwarf2_per_cu_data *iter; + VEC (dwarf2_per_cu_ptr) *result_children = NULL; + htab_t all_children; + struct symtab *symtab = get_symtab (per_cu); + + /* If we don't have a symtab, we can just skip this case. */ + if (symtab == NULL) + return; + + all_children = htab_create_alloc (1, htab_hash_pointer, htab_eq_pointer, + NULL, xcalloc, xfree); + + for (ix = 0; + VEC_iterate (dwarf2_per_cu_ptr, per_cu->imported_symtabs, + ix, iter); + ++ix) + recursively_compute_inclusions (&result_children, all_children, iter); + + /* Now we have a transitive closure of all the included CUs, and + for .gdb_index version 7 the included TUs, so we can convert it + to a list of symtabs. */ + len = VEC_length (dwarf2_per_cu_ptr, result_children); + symtab->includes + = obstack_alloc (&dwarf2_per_objfile->objfile->objfile_obstack, + (len + 1) * sizeof (struct symtab *)); + for (ix = 0; + VEC_iterate (dwarf2_per_cu_ptr, result_children, ix, iter); + ++ix) + symtab->includes[ix] = get_symtab (iter); + symtab->includes[len] = NULL; + + VEC_free (dwarf2_per_cu_ptr, result_children); + htab_delete (all_children); + } +} + +/* Compute the 'includes' field for the symtabs of all the CUs we just + read. */ + +static void +process_cu_includes (void) +{ + int ix; + struct dwarf2_per_cu_data *iter; + + for (ix = 0; + VEC_iterate (dwarf2_per_cu_ptr, dwarf2_per_objfile->just_read_cus, + ix, iter); + ++ix) + { + if (! iter->is_debug_types) + compute_symtab_includes (iter); + } + + VEC_free (dwarf2_per_cu_ptr, dwarf2_per_objfile->just_read_cus); +} + +/* Generate full symbol information for PER_CU, whose DIEs have + already been loaded into memory. */ + +static void +process_full_comp_unit (struct dwarf2_per_cu_data *per_cu, + enum language pretend_language) +{ + struct dwarf2_cu *cu = per_cu->cu; + struct objfile *objfile = per_cu->objfile; + CORE_ADDR lowpc, highpc; + struct symtab *symtab; + struct cleanup *back_to, *delayed_list_cleanup; + CORE_ADDR baseaddr; + struct block *static_block; + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + buildsym_init (); + back_to = make_cleanup (really_free_pendings, NULL); + delayed_list_cleanup = make_cleanup (free_delayed_list, cu); + + cu->list_in_scope = &file_symbols; + + cu->language = pretend_language; + cu->language_defn = language_def (cu->language); + + /* Do line number decoding in read_file_scope () */ + process_die (cu->dies, cu); + + /* For now fudge the Go package. */ + if (cu->language == language_go) + fixup_go_packaging (cu); + + /* Now that we have processed all the DIEs in the CU, all the types + should be complete, and it should now be safe to compute all of the + physnames. */ + compute_delayed_physnames (cu); + do_cleanups (delayed_list_cleanup); + + /* Some compilers don't define a DW_AT_high_pc attribute for the + compilation unit. If the DW_AT_high_pc is missing, synthesize + it, by scanning the DIE's below the compilation unit. */ + get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu); + + static_block + = end_symtab_get_static_block (highpc + baseaddr, objfile, 0, + per_cu->imported_symtabs != NULL); + + /* If the comp unit has DW_AT_ranges, it may have discontiguous ranges. + Also, DW_AT_ranges may record ranges not belonging to any child DIEs + (such as virtual method tables). Record the ranges in STATIC_BLOCK's + addrmap to help ensure it has an accurate map of pc values belonging to + this comp unit. */ + dwarf2_record_block_ranges (cu->dies, static_block, baseaddr, cu); + + symtab = end_symtab_from_static_block (static_block, objfile, + SECT_OFF_TEXT (objfile), 0); + + if (symtab != NULL) + { + int gcc_4_minor = producer_is_gcc_ge_4 (cu->producer); + + /* Set symtab language to language from DW_AT_language. If the + compilation is from a C file generated by language preprocessors, do + not set the language if it was already deduced by start_subfile. */ + if (!(cu->language == language_c && symtab->language != language_c)) + symtab->language = cu->language; + + /* GCC-4.0 has started to support -fvar-tracking. GCC-3.x still can + produce DW_AT_location with location lists but it can be possibly + invalid without -fvar-tracking. Still up to GCC-4.4.x incl. 4.4.0 + there were bugs in prologue debug info, fixed later in GCC-4.5 + by "unwind info for epilogues" patch (which is not directly related). + + For -gdwarf-4 type units LOCATIONS_VALID indication is fortunately not + needed, it would be wrong due to missing DW_AT_producer there. + + Still one can confuse GDB by using non-standard GCC compilation + options - this waits on GCC PR other/32998 (-frecord-gcc-switches). + */ + if (cu->has_loclist && gcc_4_minor >= 5) + symtab->locations_valid = 1; + + if (gcc_4_minor >= 5) + symtab->epilogue_unwind_valid = 1; + + symtab->call_site_htab = cu->call_site_htab; + } + + if (dwarf2_per_objfile->using_index) + per_cu->v.quick->symtab = symtab; + else + { + struct partial_symtab *pst = per_cu->v.psymtab; + pst->symtab = symtab; + pst->readin = 1; + } + + /* Push it for inclusion processing later. */ + VEC_safe_push (dwarf2_per_cu_ptr, dwarf2_per_objfile->just_read_cus, per_cu); + + do_cleanups (back_to); +} + +/* Generate full symbol information for type unit PER_CU, whose DIEs have + already been loaded into memory. */ + +static void +process_full_type_unit (struct dwarf2_per_cu_data *per_cu, + enum language pretend_language) +{ + struct dwarf2_cu *cu = per_cu->cu; + struct objfile *objfile = per_cu->objfile; + struct symtab *symtab; + struct cleanup *back_to, *delayed_list_cleanup; + + buildsym_init (); + back_to = make_cleanup (really_free_pendings, NULL); + delayed_list_cleanup = make_cleanup (free_delayed_list, cu); + + cu->list_in_scope = &file_symbols; + + cu->language = pretend_language; + cu->language_defn = language_def (cu->language); + + /* The symbol tables are set up in read_type_unit_scope. */ + process_die (cu->dies, cu); + + /* For now fudge the Go package. */ + if (cu->language == language_go) + fixup_go_packaging (cu); + + /* Now that we have processed all the DIEs in the CU, all the types + should be complete, and it should now be safe to compute all of the + physnames. */ + compute_delayed_physnames (cu); + do_cleanups (delayed_list_cleanup); + + /* TUs share symbol tables. + If this is the first TU to use this symtab, complete the construction + of it with end_expandable_symtab. Otherwise, complete the addition of + this TU's symbols to the existing symtab. */ + if (per_cu->type_unit_group->primary_symtab == NULL) + { + symtab = end_expandable_symtab (0, objfile, SECT_OFF_TEXT (objfile)); + per_cu->type_unit_group->primary_symtab = symtab; + + if (symtab != NULL) + { + /* Set symtab language to language from DW_AT_language. If the + compilation is from a C file generated by language preprocessors, + do not set the language if it was already deduced by + start_subfile. */ + if (!(cu->language == language_c && symtab->language != language_c)) + symtab->language = cu->language; + } + } + else + { + augment_type_symtab (objfile, + per_cu->type_unit_group->primary_symtab); + symtab = per_cu->type_unit_group->primary_symtab; + } + + if (dwarf2_per_objfile->using_index) + per_cu->v.quick->symtab = symtab; + else + { + struct partial_symtab *pst = per_cu->v.psymtab; + pst->symtab = symtab; + pst->readin = 1; + } + + do_cleanups (back_to); +} + +/* Process an imported unit DIE. */ + +static void +process_imported_unit_die (struct die_info *die, struct dwarf2_cu *cu) +{ + struct attribute *attr; + + /* For now we don't handle imported units in type units. */ + if (cu->per_cu->is_debug_types) + { + error (_("Dwarf Error: DW_TAG_imported_unit is not" + " supported in type units [in module %s]"), + cu->objfile->name); + } + + attr = dwarf2_attr (die, DW_AT_import, cu); + if (attr != NULL) + { + struct dwarf2_per_cu_data *per_cu; + struct symtab *imported_symtab; + sect_offset offset; + int is_dwz; + + offset = dwarf2_get_ref_die_offset (attr); + is_dwz = (attr->form == DW_FORM_GNU_ref_alt || cu->per_cu->is_dwz); + per_cu = dwarf2_find_containing_comp_unit (offset, is_dwz, cu->objfile); + + /* Queue the unit, if needed. */ + if (maybe_queue_comp_unit (cu, per_cu, cu->language)) + load_full_comp_unit (per_cu, cu->language); + + VEC_safe_push (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs, + per_cu); + } +} + +/* Process a die and its children. */ + +static void +process_die (struct die_info *die, struct dwarf2_cu *cu) +{ + switch (die->tag) + { + case DW_TAG_padding: + break; + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + read_file_scope (die, cu); + break; + case DW_TAG_type_unit: + read_type_unit_scope (die, cu); + break; + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + read_func_scope (die, cu); + break; + case DW_TAG_lexical_block: + case DW_TAG_try_block: + case DW_TAG_catch_block: + read_lexical_block_scope (die, cu); + break; + case DW_TAG_GNU_call_site: + read_call_site_scope (die, cu); + break; + case DW_TAG_class_type: + case DW_TAG_interface_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + process_structure_scope (die, cu); + break; + case DW_TAG_enumeration_type: + process_enumeration_scope (die, cu); + break; + + /* These dies have a type, but processing them does not create + a symbol or recurse to process the children. Therefore we can + read them on-demand through read_type_die. */ + case DW_TAG_subroutine_type: + case DW_TAG_set_type: + case DW_TAG_array_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + case DW_TAG_reference_type: + case DW_TAG_string_type: + break; + + 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); + break; + case DW_TAG_common_block: + read_common_block (die, cu); + break; + case DW_TAG_common_inclusion: + break; + case DW_TAG_namespace: + cu->processing_has_namespace_info = 1; + read_namespace (die, cu); + break; + case DW_TAG_module: + cu->processing_has_namespace_info = 1; + read_module (die, cu); + break; + case DW_TAG_imported_declaration: + case DW_TAG_imported_module: + cu->processing_has_namespace_info = 1; + 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; + + case DW_TAG_imported_unit: + process_imported_unit_die (die, cu); + break; + + default: + new_symbol (die, NULL, cu); + break; + } +} + +/* A helper function for dwarf2_compute_name which determines whether DIE + needs to have the name of the scope prepended to the name listed in the + die. */ + +static int +die_needs_namespace (struct die_info *die, struct dwarf2_cu *cu) +{ + struct attribute *attr; + + switch (die->tag) + { + case DW_TAG_namespace: + case DW_TAG_typedef: + case DW_TAG_class_type: + case DW_TAG_interface_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_enumeration_type: + case DW_TAG_enumerator: + case DW_TAG_subprogram: + case DW_TAG_member: + return 1; + + case DW_TAG_variable: + case DW_TAG_constant: + /* We only need to prefix "globally" visible variables. These include + any variable marked with DW_AT_external or any variable that + lives in a namespace. [Variables in anonymous namespaces + require prefixing, but they are not DW_AT_external.] */ + + if (dwarf2_attr (die, DW_AT_specification, cu)) + { + struct dwarf2_cu *spec_cu = cu; + + return die_needs_namespace (die_specification (die, &spec_cu), + spec_cu); + } + + attr = dwarf2_attr (die, DW_AT_external, cu); + if (attr == NULL && die->parent->tag != DW_TAG_namespace + && die->parent->tag != DW_TAG_module) + return 0; + /* A variable in a lexical block of some kind does not need a + namespace, even though in C++ such variables may be external + and have a mangled name. */ + if (die->parent->tag == DW_TAG_lexical_block + || die->parent->tag == DW_TAG_try_block + || die->parent->tag == DW_TAG_catch_block + || die->parent->tag == DW_TAG_subprogram) + return 0; + return 1; + + default: + return 0; + } +} + +/* Retrieve the last character from a mem_file. */ + +static void +do_ui_file_peek_last (void *object, const char *buffer, long length) +{ + char *last_char_p = (char *) object; + + if (length > 0) + *last_char_p = buffer[length - 1]; +} + +/* Compute the fully qualified name of DIE in CU. If PHYSNAME is nonzero, + compute the physname for the object, which include a method's: + - formal parameters (C++/Java), + - receiver type (Go), + - return type (Java). + + The term "physname" is a bit confusing. + For C++, for example, it is the demangled name. + For Go, for example, it's the mangled name. + + For Ada, return the DIE's linkage name rather than the fully qualified + name. PHYSNAME is ignored.. + + The result is allocated on the objfile_obstack and canonicalized. */ + +static const char * +dwarf2_compute_name (const char *name, + struct die_info *die, struct dwarf2_cu *cu, + int physname) +{ + struct objfile *objfile = cu->objfile; + + if (name == NULL) + name = dwarf2_name (die, cu); + + /* For Fortran GDB prefers DW_AT_*linkage_name if present but otherwise + compute it by typename_concat inside GDB. */ + if (cu->language == language_ada + || (cu->language == language_fortran && physname)) + { + /* For Ada unit, we prefer the linkage name over the name, as + the former contains the exported name, which the user expects + to be able to reference. Ideally, we want the user to be able + to reference this entity using either natural or linkage name, + but we haven't started looking at this enhancement yet. */ + struct attribute *attr; + + attr = dwarf2_attr (die, DW_AT_linkage_name, cu); + if (attr == NULL) + attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); + if (attr && DW_STRING (attr)) + return DW_STRING (attr); + } + + /* These are the only languages we know how to qualify names in. */ + if (name != NULL + && (cu->language == language_cplus || cu->language == language_java + || cu->language == language_fortran)) + { + if (die_needs_namespace (die, cu)) + { + long length; + const char *prefix; + struct ui_file *buf; + + prefix = determine_prefix (die, cu); + buf = mem_fileopen (); + if (*prefix != '\0') + { + char *prefixed_name = typename_concat (NULL, prefix, name, + physname, cu); + + fputs_unfiltered (prefixed_name, buf); + xfree (prefixed_name); + } + else + fputs_unfiltered (name, buf); + + /* Template parameters may be specified in the DIE's DW_AT_name, or + as children with DW_TAG_template_type_param or + DW_TAG_value_type_param. If the latter, add them to the name + here. If the name already has template parameters, then + skip this step; some versions of GCC emit both, and + it is more efficient to use the pre-computed name. + + Something to keep in mind about this process: it is very + unlikely, or in some cases downright impossible, to produce + something that will match the mangled name of a function. + If the definition of the function has the same debug info, + we should be able to match up with it anyway. But fallbacks + using the minimal symbol, for instance to find a method + implemented in a stripped copy of libstdc++, will not work. + If we do not have debug info for the definition, we will have to + match them up some other way. + + When we do name matching there is a related problem with function + templates; two instantiated function templates are allowed to + differ only by their return types, which we do not add here. */ + + if (cu->language == language_cplus && strchr (name, '<') == NULL) + { + struct attribute *attr; + struct die_info *child; + int first = 1; + + die->building_fullname = 1; + + for (child = die->child; child != NULL; child = child->sibling) + { + struct type *type; + LONGEST value; + gdb_byte *bytes; + struct dwarf2_locexpr_baton *baton; + struct value *v; + + if (child->tag != DW_TAG_template_type_param + && child->tag != DW_TAG_template_value_param) + continue; + + if (first) + { + fputs_unfiltered ("<", buf); + first = 0; + } + else + fputs_unfiltered (", ", buf); + + attr = dwarf2_attr (child, DW_AT_type, cu); + if (attr == NULL) + { + complaint (&symfile_complaints, + _("template parameter missing DW_AT_type")); + fputs_unfiltered ("UNKNOWN_TYPE", buf); + continue; + } + type = die_type (child, cu); + + if (child->tag == DW_TAG_template_type_param) + { + c_print_type (type, "", buf, -1, 0, &type_print_raw_options); + continue; + } + + attr = dwarf2_attr (child, DW_AT_const_value, cu); + if (attr == NULL) + { + complaint (&symfile_complaints, + _("template parameter missing " + "DW_AT_const_value")); + fputs_unfiltered ("UNKNOWN_VALUE", buf); + continue; + } + + dwarf2_const_value_attr (attr, type, name, + &cu->comp_unit_obstack, cu, + &value, &bytes, &baton); + + if (TYPE_NOSIGN (type)) + /* GDB prints characters as NUMBER 'CHAR'. If that's + changed, this can use value_print instead. */ + c_printchar (value, type, buf); + else + { + struct value_print_options opts; + + if (baton != NULL) + v = dwarf2_evaluate_loc_desc (type, NULL, + baton->data, + baton->size, + baton->per_cu); + else if (bytes != NULL) + { + v = allocate_value (type); + memcpy (value_contents_writeable (v), bytes, + TYPE_LENGTH (type)); + } + else + v = value_from_longest (type, value); + + /* Specify decimal so that we do not depend on + the radix. */ + get_formatted_print_options (&opts, 'd'); + opts.raw = 1; + value_print (v, buf, &opts); + release_value (v); + value_free (v); + } + } - default: - error (_("Dwarf Error: Cannot handle %s " - "in DWARF reader [in module %s]"), - dwarf_form_name (form), - bfd_get_filename (abfd)); + die->building_fullname = 0; + + if (!first) + { + /* Close the argument list, with a space if necessary + (nested templates). */ + char last_char = '\0'; + ui_file_put (buf, do_ui_file_peek_last, &last_char); + if (last_char == '>') + fputs_unfiltered (" >", buf); + else + fputs_unfiltered (">", buf); + } + } + + /* For Java and C++ methods, append formal parameter type + information, if PHYSNAME. */ + + if (physname && die->tag == DW_TAG_subprogram + && (cu->language == language_cplus + || cu->language == language_java)) + { + struct type *type = read_type_die (die, cu); + + c_type_print_args (type, buf, 1, cu->language, + &type_print_raw_options); + + if (cu->language == language_java) + { + /* For java, we must append the return type to method + names. */ + if (die->tag == DW_TAG_subprogram) + java_print_type (TYPE_TARGET_TYPE (type), "", buf, + 0, 0, &type_print_raw_options); + } + else if (cu->language == language_cplus) + { + /* Assume that an artificial first parameter is + "this", but do not crash if it is not. RealView + marks unnamed (and thus unused) parameters as + artificial; there is no way to differentiate + the two cases. */ + if (TYPE_NFIELDS (type) > 0 + && TYPE_FIELD_ARTIFICIAL (type, 0) + && TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_PTR + && TYPE_CONST (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, + 0)))) + fputs_unfiltered (" const", buf); + } + } + + name = ui_file_obsavestring (buf, &objfile->objfile_obstack, + &length); + ui_file_delete (buf); + + if (cu->language == language_cplus) + { + const char *cname + = dwarf2_canonicalize_name (name, cu, + &objfile->objfile_obstack); + + if (cname != NULL) + name = cname; + } } } - if (abbrev->has_children) - return skip_children (buffer, info_ptr, cu); - else - return info_ptr; + return name; } -/* Locate ORIG_PDI's sibling. - INFO_PTR should point to the start of the next DIE after ORIG_PDI - in BUFFER. */ +/* Return the fully qualified name of DIE, based on its DW_AT_name. + If scope qualifiers are appropriate they will be added. The result + will be allocated on the objfile_obstack, or NULL if the DIE does + not have a name. NAME may either be from a previous call to + dwarf2_name or NULL. -static gdb_byte * -locate_pdi_sibling (struct partial_die_info *orig_pdi, - gdb_byte *buffer, gdb_byte *info_ptr, - bfd *abfd, struct dwarf2_cu *cu) + The output string will be canonicalized (if C++/Java). */ + +static const char * +dwarf2_full_name (const char *name, struct die_info *die, struct dwarf2_cu *cu) { - /* Do we know the sibling already? */ + return dwarf2_compute_name (name, die, cu, 0); +} - if (orig_pdi->sibling) - return orig_pdi->sibling; +/* Construct a physname for the given DIE in CU. NAME may either be + from a previous call to dwarf2_name or NULL. The result will be + allocated on the objfile_objstack or NULL if the DIE does not have a + name. - /* Are there any children to deal with? */ + The output string will be canonicalized (if C++/Java). */ - if (!orig_pdi->has_children) - return info_ptr; +static const char * +dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu) +{ + struct objfile *objfile = cu->objfile; + struct attribute *attr; + const char *retval, *mangled = NULL, *canon = NULL; + struct cleanup *back_to; + int need_copy = 1; - /* Skip the children the long way. */ + /* In this case dwarf2_compute_name is just a shortcut not building anything + on its own. */ + if (!die_needs_namespace (die, cu)) + return dwarf2_compute_name (name, die, cu, 1); - return skip_children (buffer, info_ptr, cu); -} + back_to = make_cleanup (null_cleanup, NULL); -/* Expand this partial symbol table into a full symbol table. */ + attr = dwarf2_attr (die, DW_AT_linkage_name, cu); + if (!attr) + attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); -static void -dwarf2_psymtab_to_symtab (struct partial_symtab *pst) -{ - if (pst != NULL) + /* DW_AT_linkage_name is missing in some cases - depend on what GDB + has computed. */ + if (attr && DW_STRING (attr)) + { + char *demangled; + + mangled = DW_STRING (attr); + + /* Use DMGL_RET_DROP for C++ template functions to suppress their return + type. It is easier for GDB users to search for such functions as + `name(params)' than `long name(params)'. In such case the minimal + symbol names do not match the full symbol names but for template + functions there is never a need to look up their definition from their + declaration so the only disadvantage remains the minimal symbol + variant `long name(params)' does not have the proper inferior type. + */ + + if (cu->language == language_go) + { + /* This is a lie, but we already lie to the caller new_symbol_full. + new_symbol_full assumes we return the mangled name. + This just undoes that lie until things are cleaned up. */ + demangled = NULL; + } + else + { + demangled = cplus_demangle (mangled, + (DMGL_PARAMS | DMGL_ANSI + | (cu->language == language_java + ? DMGL_JAVA | DMGL_RET_POSTFIX + : DMGL_RET_DROP))); + } + if (demangled) + { + make_cleanup (xfree, demangled); + canon = demangled; + } + else + { + canon = mangled; + need_copy = 0; + } + } + + if (canon == NULL || check_physname) { - if (pst->readin) + const char *physname = dwarf2_compute_name (name, die, cu, 1); + + if (canon != NULL && strcmp (physname, canon) != 0) { - warning (_("bug: psymtab for %s is already read in."), - pst->filename); + /* It may not mean a bug in GDB. The compiler could also + compute DW_AT_linkage_name incorrectly. But in such case + GDB would need to be bug-to-bug compatible. */ + + complaint (&symfile_complaints, + _("Computed physname <%s> does not match demangled <%s> " + "(from linkage <%s>) - DIE at 0x%x [in module %s]"), + physname, canon, mangled, die->offset.sect_off, objfile->name); + + /* Prefer DW_AT_linkage_name (in the CANON form) - when it + is available here - over computed PHYSNAME. It is safer + against both buggy GDB and buggy compilers. */ + + retval = canon; } else { - if (info_verbose) - { - printf_filtered (_("Reading in symbols for %s..."), - pst->filename); - gdb_flush (gdb_stdout); - } + retval = physname; + need_copy = 0; + } + } + else + retval = canon; + + if (need_copy) + retval = obstack_copy0 (&objfile->objfile_obstack, retval, strlen (retval)); + + do_cleanups (back_to); + return retval; +} + +/* 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 objfile *objfile = cu->objfile; + struct attribute *import_attr; + struct die_info *imported_die, *child_die; + struct dwarf2_cu *imported_cu; + const char *imported_name; + const char *imported_name_prefix; + const char *canonical_name; + const char *import_alias; + const char *imported_declaration = NULL; + const char *import_prefix; + VEC (const_char_ptr) *excludes = NULL; + struct cleanup *cleanups; + + 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_cu = cu; + imported_die = follow_die_ref_or_sig (die, import_attr, &imported_cu); + imported_name = dwarf2_name (imported_die, imported_cu); + if (imported_name == NULL) + { + /* GCC bug: https://bugzilla.redhat.com/show_bug.cgi?id=506524 + + The import in the following code: + namespace A + { + typedef int B; + } + + int main () + { + using A::B; + B b; + return b; + } + + ... + <2><51>: Abbrev Number: 3 (DW_TAG_imported_declaration) + <52> DW_AT_decl_file : 1 + <53> DW_AT_decl_line : 6 + <54> DW_AT_import : <0x75> + <2><58>: Abbrev Number: 4 (DW_TAG_typedef) + <59> DW_AT_name : B + <5b> DW_AT_decl_file : 1 + <5c> DW_AT_decl_line : 2 + <5d> DW_AT_type : <0x6e> + ... + <1><75>: Abbrev Number: 7 (DW_TAG_base_type) + <76> DW_AT_byte_size : 4 + <77> DW_AT_encoding : 5 (signed) + + imports the wrong die ( 0x75 instead of 0x58 ). + This case will be ignored until the gcc bug is fixed. */ + return; + } + + /* Figure out the local name after import. */ + import_alias = dwarf2_name (die, cu); - /* Restore our global data. */ - dwarf2_per_objfile = objfile_data (pst->objfile, - dwarf2_objfile_data_key); + /* 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, imported_cu); - /* If this psymtab is constructed from a debug-only objfile, the - has_section_at_zero flag will not necessarily be correct. We - can get the correct value for this flag by looking at the data - associated with the (presumably stripped) associated objfile. */ - if (pst->objfile->separate_debug_objfile_backlink) - { - struct dwarf2_per_objfile *dpo_backlink - = objfile_data (pst->objfile->separate_debug_objfile_backlink, - dwarf2_objfile_data_key); + if (imported_die->tag != DW_TAG_namespace + && imported_die->tag != DW_TAG_module) + { + imported_declaration = imported_name; + canonical_name = imported_name_prefix; + } + else if (strlen (imported_name_prefix) > 0) + canonical_name = obconcat (&objfile->objfile_obstack, + imported_name_prefix, "::", imported_name, + (char *) NULL); + else + canonical_name = imported_name; - dwarf2_per_objfile->has_section_at_zero - = dpo_backlink->has_section_at_zero; - } + cleanups = make_cleanup (VEC_cleanup (const_char_ptr), &excludes); - dwarf2_per_objfile->reading_partial_symbols = 0; + if (die->tag == DW_TAG_imported_module && cu->language == language_fortran) + for (child_die = die->child; child_die && child_die->tag; + child_die = sibling_die (child_die)) + { + /* DWARF-4: A Fortran use statement with a “rename list” may be + represented by an imported module entry with an import attribute + referring to the module and owned entries corresponding to those + entities that are renamed as part of being imported. */ - psymtab_to_symtab_1 (pst); + if (child_die->tag != DW_TAG_imported_declaration) + { + complaint (&symfile_complaints, + _("child DW_TAG_imported_declaration expected " + "- DIE at 0x%x [in module %s]"), + child_die->offset.sect_off, objfile->name); + continue; + } - /* Finish up the debug error message. */ - if (info_verbose) - printf_filtered (_("done.\n")); - } - } -} + import_attr = dwarf2_attr (child_die, DW_AT_import, cu); + if (import_attr == NULL) + { + complaint (&symfile_complaints, _("Tag '%s' has no DW_AT_import"), + dwarf_tag_name (child_die->tag)); + continue; + } -/* Add PER_CU to the queue. */ + imported_cu = cu; + imported_die = follow_die_ref_or_sig (child_die, import_attr, + &imported_cu); + imported_name = dwarf2_name (imported_die, imported_cu); + if (imported_name == NULL) + { + complaint (&symfile_complaints, + _("child DW_TAG_imported_declaration has unknown " + "imported name - DIE at 0x%x [in module %s]"), + child_die->offset.sect_off, objfile->name); + continue; + } -static void -queue_comp_unit (struct dwarf2_per_cu_data *per_cu, struct objfile *objfile) -{ - struct dwarf2_queue_item *item; + VEC_safe_push (const_char_ptr, excludes, imported_name); - per_cu->queued = 1; - item = xmalloc (sizeof (*item)); - item->per_cu = per_cu; - item->next = NULL; + process_die (child_die, cu); + } - if (dwarf2_queue == NULL) - dwarf2_queue = item; - else - dwarf2_queue_tail->next = item; + cp_add_using_directive (import_prefix, + canonical_name, + import_alias, + imported_declaration, + excludes, + 0, + &objfile->objfile_obstack); - dwarf2_queue_tail = item; + do_cleanups (cleanups); } -/* Process the queue. */ +/* Cleanup function for handle_DW_AT_stmt_list. */ static void -process_queue (struct objfile *objfile) +free_cu_line_header (void *arg) { - struct dwarf2_queue_item *item, *next_item; - - /* The queue starts out with one item, but following a DIE reference - may load a new CU, adding it to the end of the queue. */ - for (item = dwarf2_queue; item != NULL; dwarf2_queue = item = next_item) - { - if (dwarf2_per_objfile->using_index - ? !item->per_cu->v.quick->symtab - : (item->per_cu->v.psymtab && !item->per_cu->v.psymtab->readin)) - process_full_comp_unit (item->per_cu); - - item->per_cu->queued = 0; - next_item = item->next; - xfree (item); - } + struct dwarf2_cu *cu = arg; - dwarf2_queue_tail = NULL; + free_line_header (cu->line_header); + cu->line_header = NULL; } -/* Free all allocated queue entries. This function only releases anything if - an error was thrown; if the queue was processed then it would have been - freed as we went along. */ +/* Check for possibly missing DW_AT_comp_dir with relative .debug_line + directory paths. GCC SVN r127613 (new option -fdebug-prefix-map) fixed + this, it was first present in GCC release 4.3.0. */ -static void -dwarf2_release_queue (void *dummy) +static int +producer_is_gcc_lt_4_3 (struct dwarf2_cu *cu) { - struct dwarf2_queue_item *item, *last; - - item = dwarf2_queue; - while (item) - { - /* Anything still marked queued is likely to be in an - inconsistent state, so discard it. */ - if (item->per_cu->queued) - { - if (item->per_cu->cu != NULL) - free_one_cached_comp_unit (item->per_cu->cu); - item->per_cu->queued = 0; - } - - last = item; - item = item->next; - xfree (last); - } + if (!cu->checked_producer) + check_producer (cu); - dwarf2_queue = dwarf2_queue_tail = NULL; + return cu->producer_is_gcc_lt_4_3; } -/* Read in full symbols for PST, and anything it depends on. */ - static void -psymtab_to_symtab_1 (struct partial_symtab *pst) +find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu, + const char **name, const char **comp_dir) { - struct dwarf2_per_cu_data *per_cu; - struct cleanup *back_to; - int i; + struct attribute *attr; - for (i = 0; i < pst->number_of_dependencies; i++) - if (!pst->dependencies[i]->readin) - { - /* Inform about additional files that need to be read in. */ - if (info_verbose) - { - /* FIXME: i18n: Need to make this a single string. */ - fputs_filtered (" ", gdb_stdout); - wrap_here (""); - fputs_filtered ("and ", gdb_stdout); - wrap_here (""); - printf_filtered ("%s...", pst->dependencies[i]->filename); - wrap_here (""); /* Flush output. */ - gdb_flush (gdb_stdout); - } - psymtab_to_symtab_1 (pst->dependencies[i]); - } + *name = NULL; + *comp_dir = NULL; - per_cu = pst->read_symtab_private; + /* Find the filename. Do not use dwarf2_name here, since the filename + is not a source language identifier. */ + attr = dwarf2_attr (die, DW_AT_name, cu); + if (attr) + { + *name = DW_STRING (attr); + } - if (per_cu == NULL) + attr = dwarf2_attr (die, DW_AT_comp_dir, cu); + if (attr) + *comp_dir = DW_STRING (attr); + else if (producer_is_gcc_lt_4_3 (cu) && *name != NULL + && IS_ABSOLUTE_PATH (*name)) { - /* It's an include file, no symbols to read for it. - Everything is in the parent symtab. */ - pst->readin = 1; - return; + char *d = ldirname (*name); + + *comp_dir = d; + if (d != NULL) + make_cleanup (xfree, d); + } + if (*comp_dir != NULL) + { + /* Irix 6.2 native cc prepends .: to the compilation + directory, get rid of it. */ + char *cp = strchr (*comp_dir, ':'); + + if (cp && cp != *comp_dir && cp[-1] == '.' && cp[1] == '/') + *comp_dir = cp + 1; } - dw2_do_instantiate_symtab (pst->objfile, per_cu); + if (*name == NULL) + *name = ""; } -/* Load the DIEs associated with PER_CU into memory. */ +/* Handle DW_AT_stmt_list for a compilation unit. + DIE is the DW_TAG_compile_unit die for CU. + COMP_DIR is the compilation directory. + WANT_LINE_INFO is non-zero if the pc/line-number mapping is needed. */ static void -load_full_comp_unit (struct dwarf2_per_cu_data *per_cu, - struct objfile *objfile) +handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu, + const char *comp_dir) { - bfd *abfd = objfile->obfd; - struct dwarf2_cu *cu; - unsigned int offset; - gdb_byte *info_ptr, *beg_of_comp_unit; - struct cleanup *free_abbrevs_cleanup = NULL, *free_cu_cleanup = NULL; struct attribute *attr; - int read_cu = 0; - gdb_assert (! per_cu->debug_types_section); + gdb_assert (! cu->per_cu->is_debug_types); - /* Set local variables from the partial symbol table info. */ - offset = per_cu->offset; - - dwarf2_read_section (objfile, &dwarf2_per_objfile->info); - info_ptr = dwarf2_per_objfile->info.buffer + offset; - beg_of_comp_unit = info_ptr; - - if (per_cu->cu == NULL) + attr = dwarf2_attr (die, DW_AT_stmt_list, cu); + if (attr) { - cu = xmalloc (sizeof (*cu)); - init_one_comp_unit (cu, objfile); - - read_cu = 1; - - /* If an error occurs while loading, release our storage. */ - free_cu_cleanup = make_cleanup (free_one_comp_unit, cu); - - /* Read in the comp_unit header. */ - info_ptr = read_comp_unit_head (&cu->header, info_ptr, abfd); + unsigned int line_offset = DW_UNSND (attr); + struct line_header *line_header + = dwarf_decode_line_header (line_offset, cu); - /* Skip dummy compilation units. */ - if (info_ptr >= (dwarf2_per_objfile->info.buffer - + dwarf2_per_objfile->info.size) - || peek_abbrev_code (abfd, info_ptr) == 0) + if (line_header) { - do_cleanups (free_cu_cleanup); - return; + cu->line_header = line_header; + make_cleanup (free_cu_line_header, cu); + dwarf_decode_lines (line_header, comp_dir, cu, NULL, 1); } + } +} - /* Complete the cu_header. */ - cu->header.offset = offset; - cu->header.first_die_offset = info_ptr - beg_of_comp_unit; - - /* Read the abbrevs for this compilation unit. */ - dwarf2_read_abbrevs (abfd, cu); - free_abbrevs_cleanup = make_cleanup (dwarf2_free_abbrev_table, cu); +/* Process DW_TAG_compile_unit or DW_TAG_partial_unit. */ - /* Link this compilation unit into the compilation unit tree. */ - per_cu->cu = cu; - cu->per_cu = per_cu; +static void +read_file_scope (struct die_info *die, struct dwarf2_cu *cu) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct cleanup *back_to = make_cleanup (null_cleanup, 0); + CORE_ADDR lowpc = ((CORE_ADDR) -1); + CORE_ADDR highpc = ((CORE_ADDR) 0); + struct attribute *attr; + const char *name = NULL; + const char *comp_dir = NULL; + struct die_info *child_die; + bfd *abfd = objfile->obfd; + CORE_ADDR baseaddr; - /* Link this CU into read_in_chain. */ - per_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain; - dwarf2_per_objfile->read_in_chain = per_cu; - } - else - { - cu = per_cu->cu; - info_ptr += cu->header.first_die_offset; - } + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - cu->dies = read_comp_unit (info_ptr, cu); + get_scope_pc_bounds (die, &lowpc, &highpc, cu); - /* We try not to read any attributes in this function, because not - all objfiles needed for references have been loaded yet, and symbol - table processing isn't initialized. But we have to set the CU language, - or we won't be able to build types correctly. */ - prepare_one_comp_unit (cu, cu->dies); + /* If we didn't find a lowpc, set it to highpc to avoid complaints + from finish_block. */ + if (lowpc == ((CORE_ADDR) -1)) + lowpc = highpc; + lowpc += baseaddr; + highpc += baseaddr; - /* Similarly, if we do not read the producer, we can not apply - producer-specific interpretation. */ - attr = dwarf2_attr (cu->dies, DW_AT_producer, cu); - if (attr) - cu->producer = DW_STRING (attr); + find_file_and_directory (die, cu, &name, &comp_dir); - if (read_cu) - { - do_cleanups (free_abbrevs_cleanup); + prepare_one_comp_unit (cu, die, cu->language); - /* We've successfully allocated this compilation unit. Let our - caller clean it up when finished with it. */ - discard_cleanups (free_cu_cleanup); - } -} + /* The XLCL doesn't generate DW_LANG_OpenCL because this attribute is not + standardised yet. As a workaround for the language detection we fall + back to the DW_AT_producer string. */ + if (cu->producer && strstr (cu->producer, "IBM XL C for OpenCL") != NULL) + cu->language = language_opencl; -/* Add a DIE to the delayed physname list. */ + /* Similar hack for Go. */ + if (cu->producer && strstr (cu->producer, "GNU Go ") != NULL) + set_cu_language (DW_LANG_Go, cu); -static void -add_to_method_list (struct type *type, int fnfield_index, int index, - const char *name, struct die_info *die, - struct dwarf2_cu *cu) -{ - struct delayed_method_info mi; - mi.type = type; - mi.fnfield_index = fnfield_index; - mi.index = index; - mi.name = name; - mi.die = die; - VEC_safe_push (delayed_method_info, cu->method_list, &mi); -} + dwarf2_start_symtab (cu, name, comp_dir, lowpc); -/* A cleanup for freeing the delayed method list. */ + /* Decode line number information if present. We do this before + processing child DIEs, so that the line header table is available + for DW_AT_decl_file. */ + handle_DW_AT_stmt_list (die, cu, comp_dir); -static void -free_delayed_list (void *ptr) -{ - struct dwarf2_cu *cu = (struct dwarf2_cu *) ptr; - if (cu->method_list != NULL) + /* Process all dies in compilation unit. */ + if (die->child != NULL) { - VEC_free (delayed_method_info, cu->method_list); - cu->method_list = NULL; + child_die = die->child; + while (child_die && child_die->tag) + { + process_die (child_die, cu); + child_die = sibling_die (child_die); + } } -} - -/* Compute the physnames of any methods on the CU's method list. - The computation of method physnames is delayed in order to avoid the - (bad) condition that one of the method's formal parameters is of an as yet - incomplete type. */ + /* Decode macro information, if present. Dwarf 2 macro information + refers to information in the line number info statement program + header, so we can only read it if we've read the header + successfully. */ + attr = dwarf2_attr (die, DW_AT_GNU_macros, cu); + if (attr && cu->line_header) + { + if (dwarf2_attr (die, DW_AT_macro_info, cu)) + complaint (&symfile_complaints, + _("CU refers to both DW_AT_GNU_macros and DW_AT_macro_info")); -static void -compute_delayed_physnames (struct dwarf2_cu *cu) -{ - int i; - struct delayed_method_info *mi; - for (i = 0; VEC_iterate (delayed_method_info, cu->method_list, i, mi) ; ++i) + dwarf_decode_macros (cu, DW_UNSND (attr), comp_dir, 1); + } + else { - const char *physname; - struct fn_fieldlist *fn_flp - = &TYPE_FN_FIELDLIST (mi->type, mi->fnfield_index); - physname = dwarf2_physname ((char *) mi->name, mi->die, cu); - fn_flp->fn_fields[mi->index].physname = physname ? physname : ""; + attr = dwarf2_attr (die, DW_AT_macro_info, cu); + if (attr && cu->line_header) + { + unsigned int macro_offset = DW_UNSND (attr); + + dwarf_decode_macros (cu, macro_offset, comp_dir, 0); + } } + + do_cleanups (back_to); } -/* Generate full symbol information for PST and CU, whose DIEs have - already been loaded into memory. */ +/* TU version of handle_DW_AT_stmt_list for read_type_unit_scope. + Create the set of symtabs used by this TU, or if this TU is sharing + symtabs with another TU and the symtabs have already been created + then restore those symtabs in the line header. + We don't need the pc/line-number mapping for type units. */ static void -process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) +setup_type_unit_groups (struct die_info *die, struct dwarf2_cu *cu) { - struct dwarf2_cu *cu = per_cu->cu; - struct objfile *objfile = per_cu->objfile; - CORE_ADDR lowpc, highpc; - struct symtab *symtab; - struct cleanup *back_to, *delayed_list_cleanup; - CORE_ADDR baseaddr; - - baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_per_cu_data *per_cu = cu->per_cu; + struct type_unit_group *tu_group; + int first_time; + struct line_header *lh; + struct attribute *attr; + unsigned int i, line_offset; - buildsym_init (); - back_to = make_cleanup (really_free_pendings, NULL); - delayed_list_cleanup = make_cleanup (free_delayed_list, cu); + gdb_assert (per_cu->is_debug_types); - cu->list_in_scope = &file_symbols; + attr = dwarf2_attr (die, DW_AT_stmt_list, cu); - /* Do line number decoding in read_file_scope () */ - process_die (cu->dies, cu); + /* If we're using .gdb_index (includes -readnow) then + per_cu->s.type_unit_group may not have been set up yet. */ + if (per_cu->type_unit_group == NULL) + per_cu->type_unit_group = get_type_unit_group (cu, attr); + tu_group = per_cu->type_unit_group; - /* Now that we have processed all the DIEs in the CU, all the types - should be complete, and it should now be safe to compute all of the - physnames. */ - compute_delayed_physnames (cu); - do_cleanups (delayed_list_cleanup); + /* If we've already processed this stmt_list there's no real need to + do it again, we could fake it and just recreate the part we need + (file name,index -> symtab mapping). If data shows this optimization + is useful we can do it then. */ + first_time = tu_group->primary_symtab == NULL; - /* Some compilers don't define a DW_AT_high_pc attribute for the - compilation unit. If the DW_AT_high_pc is missing, synthesize - it, by scanning the DIE's below the compilation unit. */ - get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu); + /* We have to handle the case of both a missing DW_AT_stmt_list or bad + debug info. */ + lh = NULL; + if (attr != NULL) + { + line_offset = DW_UNSND (attr); + lh = dwarf_decode_line_header (line_offset, cu); + } + if (lh == NULL) + { + if (first_time) + dwarf2_start_symtab (cu, "", NULL, 0); + else + { + gdb_assert (tu_group->symtabs == NULL); + restart_symtab (0); + } + /* Note: The primary symtab will get allocated at the end. */ + return; + } - symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile)); + cu->line_header = lh; + make_cleanup (free_cu_line_header, cu); - if (symtab != NULL) + if (first_time) { - int gcc_4_minor = producer_is_gcc_ge_4 (cu->producer); + dwarf2_start_symtab (cu, "", NULL, 0); - /* Set symtab language to language from DW_AT_language. If the - compilation is from a C file generated by language preprocessors, do - not set the language if it was already deduced by start_subfile. */ - if (!(cu->language == language_c && symtab->language != language_c)) - symtab->language = cu->language; + tu_group->num_symtabs = lh->num_file_names; + tu_group->symtabs = XNEWVEC (struct symtab *, lh->num_file_names); - /* GCC-4.0 has started to support -fvar-tracking. GCC-3.x still can - produce DW_AT_location with location lists but it can be possibly - invalid without -fvar-tracking. + for (i = 0; i < lh->num_file_names; ++i) + { + char *dir = NULL; + struct file_entry *fe = &lh->file_names[i]; - For -gdwarf-4 type units LOCATIONS_VALID indication is fortunately not - needed, it would be wrong due to missing DW_AT_producer there. + if (fe->dir_index) + dir = lh->include_dirs[fe->dir_index - 1]; + dwarf2_start_subfile (fe->name, dir, NULL); - Still one can confuse GDB by using non-standard GCC compilation - options - this waits on GCC PR other/32998 (-frecord-gcc-switches). - */ - if (cu->has_loclist && gcc_4_minor >= 0) - symtab->locations_valid = 1; + /* Note: We don't have to watch for the main subfile here, type units + don't have DW_AT_name. */ - if (gcc_4_minor >= 5) - symtab->epilogue_unwind_valid = 1; + if (current_subfile->symtab == NULL) + { + /* NOTE: start_subfile will recognize when it's been passed + a file it has already seen. So we can't assume there's a + simple mapping from lh->file_names to subfiles, + lh->file_names may contain dups. */ + current_subfile->symtab = allocate_symtab (current_subfile->name, + objfile); + } - symtab->call_site_htab = cu->call_site_htab; + fe->symtab = current_subfile->symtab; + tu_group->symtabs[i] = fe->symtab; + } } - - if (dwarf2_per_objfile->using_index) - per_cu->v.quick->symtab = symtab; else { - struct partial_symtab *pst = per_cu->v.psymtab; - pst->symtab = symtab; - pst->readin = 1; + restart_symtab (0); + + for (i = 0; i < lh->num_file_names; ++i) + { + struct file_entry *fe = &lh->file_names[i]; + + fe->symtab = tu_group->symtabs[i]; + } } - do_cleanups (back_to); + /* The main symtab is allocated last. Type units don't have DW_AT_name + so they don't have a "real" (so to speak) symtab anyway. + There is later code that will assign the main symtab to all symbols + that don't have one. We need to handle the case of a symbol with a + missing symtab (DW_AT_decl_file) anyway. */ } -/* Process a die and its children. */ +/* Process DW_TAG_type_unit. + For TUs we want to skip the first top level sibling if it's not the + actual type being defined by this TU. In this case the first top + level sibling is there to provide context only. */ static void -process_die (struct die_info *die, struct dwarf2_cu *cu) +read_type_unit_scope (struct die_info *die, struct dwarf2_cu *cu) { - switch (die->tag) - { - case DW_TAG_padding: - break; - case DW_TAG_compile_unit: - read_file_scope (die, cu); - break; - case DW_TAG_type_unit: - read_type_unit_scope (die, cu); - break; - case DW_TAG_subprogram: - case DW_TAG_inlined_subroutine: - read_func_scope (die, cu); - break; - case DW_TAG_lexical_block: - case DW_TAG_try_block: - case DW_TAG_catch_block: - read_lexical_block_scope (die, cu); - break; - case DW_TAG_GNU_call_site: - read_call_site_scope (die, cu); - break; - case DW_TAG_class_type: - case DW_TAG_interface_type: - case DW_TAG_structure_type: - case DW_TAG_union_type: - process_structure_scope (die, cu); - break; - case DW_TAG_enumeration_type: - process_enumeration_scope (die, cu); - break; + struct die_info *child_die; - /* These dies have a type, but processing them does not create - a symbol or recurse to process the children. Therefore we can - read them on-demand through read_type_die. */ - case DW_TAG_subroutine_type: - case DW_TAG_set_type: - case DW_TAG_array_type: - case DW_TAG_pointer_type: - case DW_TAG_ptr_to_member_type: - case DW_TAG_reference_type: - case DW_TAG_string_type: - break; + prepare_one_comp_unit (cu, die, language_minimal); - 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); - break; - case DW_TAG_common_block: - read_common_block (die, cu); - break; - case DW_TAG_common_inclusion: - break; - case DW_TAG_namespace: - processing_has_namespace_info = 1; - read_namespace (die, cu); - break; - case DW_TAG_module: - processing_has_namespace_info = 1; - read_module (die, cu); - break; - case DW_TAG_imported_declaration: - case DW_TAG_imported_module: - processing_has_namespace_info = 1; - 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); - break; + /* Initialize (or reinitialize) the machinery for building symtabs. + We do this before processing child DIEs, so that the line header table + is available for DW_AT_decl_file. */ + setup_type_unit_groups (die, cu); + + if (die->child != NULL) + { + child_die = die->child; + while (child_die && child_die->tag) + { + process_die (child_die, cu); + child_die = sibling_die (child_die); + } } } + +/* DWO/DWP files. -/* A helper function for dwarf2_compute_name which determines whether DIE - needs to have the name of the scope prepended to the name listed in the - die. */ + http://gcc.gnu.org/wiki/DebugFission + http://gcc.gnu.org/wiki/DebugFissionDWP + + To simplify handling of both DWO files ("object" files with the DWARF info) + and DWP files (a file with the DWOs packaged up into one file), we treat + DWP files as having a collection of virtual DWO files. */ + +static hashval_t +hash_dwo_file (const void *item) +{ + const struct dwo_file *dwo_file = item; + + return htab_hash_string (dwo_file->name); +} static int -die_needs_namespace (struct die_info *die, struct dwarf2_cu *cu) +eq_dwo_file (const void *item_lhs, const void *item_rhs) { - struct attribute *attr; + const struct dwo_file *lhs = item_lhs; + const struct dwo_file *rhs = item_rhs; - switch (die->tag) - { - case DW_TAG_namespace: - case DW_TAG_typedef: - case DW_TAG_class_type: - case DW_TAG_interface_type: - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_enumeration_type: - case DW_TAG_enumerator: - case DW_TAG_subprogram: - case DW_TAG_member: - return 1; + return strcmp (lhs->name, rhs->name) == 0; +} - case DW_TAG_variable: - case DW_TAG_constant: - /* We only need to prefix "globally" visible variables. These include - any variable marked with DW_AT_external or any variable that - lives in a namespace. [Variables in anonymous namespaces - require prefixing, but they are not DW_AT_external.] */ +/* Allocate a hash table for DWO files. */ - if (dwarf2_attr (die, DW_AT_specification, cu)) - { - struct dwarf2_cu *spec_cu = cu; +static htab_t +allocate_dwo_file_hash_table (void) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + + return htab_create_alloc_ex (41, + hash_dwo_file, + eq_dwo_file, + NULL, + &objfile->objfile_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); +} + +/* Lookup DWO file DWO_NAME. */ - return die_needs_namespace (die_specification (die, &spec_cu), - spec_cu); - } +static void ** +lookup_dwo_file_slot (const char *dwo_name) +{ + struct dwo_file find_entry; + void **slot; - attr = dwarf2_attr (die, DW_AT_external, cu); - if (attr == NULL && die->parent->tag != DW_TAG_namespace - && die->parent->tag != DW_TAG_module) - return 0; - /* A variable in a lexical block of some kind does not need a - namespace, even though in C++ such variables may be external - and have a mangled name. */ - if (die->parent->tag == DW_TAG_lexical_block - || die->parent->tag == DW_TAG_try_block - || die->parent->tag == DW_TAG_catch_block - || die->parent->tag == DW_TAG_subprogram) - return 0; - return 1; + if (dwarf2_per_objfile->dwo_files == NULL) + dwarf2_per_objfile->dwo_files = allocate_dwo_file_hash_table (); - default: - return 0; - } + memset (&find_entry, 0, sizeof (find_entry)); + find_entry.name = dwo_name; + slot = htab_find_slot (dwarf2_per_objfile->dwo_files, &find_entry, INSERT); + + return slot; } -/* Retrieve the last character from a mem_file. */ +static hashval_t +hash_dwo_unit (const void *item) +{ + const struct dwo_unit *dwo_unit = item; -static void -do_ui_file_peek_last (void *object, const char *buffer, long length) + /* This drops the top 32 bits of the id, but is ok for a hash. */ + return dwo_unit->signature; +} + +static int +eq_dwo_unit (const void *item_lhs, const void *item_rhs) { - char *last_char_p = (char *) object; + const struct dwo_unit *lhs = item_lhs; + const struct dwo_unit *rhs = item_rhs; - if (length > 0) - *last_char_p = buffer[length - 1]; + /* The signature is assumed to be unique within the DWO file. + So while object file CU dwo_id's always have the value zero, + that's OK, assuming each object file DWO file has only one CU, + and that's the rule for now. */ + return lhs->signature == rhs->signature; } -/* Compute the fully qualified name of DIE in CU. If PHYSNAME is nonzero, - compute the physname for the object, which include a method's - formal parameters (C++/Java) and return type (Java). +/* Allocate a hash table for DWO CUs,TUs. + There is one of these tables for each of CUs,TUs for each DWO file. */ - For Ada, return the DIE's linkage name rather than the fully qualified - name. PHYSNAME is ignored.. +static htab_t +allocate_dwo_unit_table (struct objfile *objfile) +{ + /* Start out with a pretty small number. + Generally DWO files contain only one CU and maybe some TUs. */ + return htab_create_alloc_ex (3, + hash_dwo_unit, + eq_dwo_unit, + NULL, + &objfile->objfile_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); +} - The result is allocated on the objfile_obstack and canonicalized. */ +/* Structure used to pass data to create_dwo_debug_info_hash_table_reader. */ -static const char * -dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu, - int physname) +struct create_dwo_info_table_data { - if (name == NULL) - name = dwarf2_name (die, cu); + struct dwo_file *dwo_file; + htab_t cu_htab; +}; - /* For Fortran GDB prefers DW_AT_*linkage_name if present but otherwise - compute it by typename_concat inside GDB. */ - if (cu->language == language_ada - || (cu->language == language_fortran && physname)) - { - /* For Ada unit, we prefer the linkage name over the name, as - the former contains the exported name, which the user expects - to be able to reference. Ideally, we want the user to be able - to reference this entity using either natural or linkage name, - but we haven't started looking at this enhancement yet. */ - struct attribute *attr; +/* die_reader_func for create_dwo_debug_info_hash_table. */ - attr = dwarf2_attr (die, DW_AT_linkage_name, cu); - if (attr == NULL) - attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); - if (attr && DW_STRING (attr)) - return DW_STRING (attr); +static void +create_dwo_debug_info_hash_table_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *datap) +{ + struct dwarf2_cu *cu = reader->cu; + struct objfile *objfile = dwarf2_per_objfile->objfile; + sect_offset offset = cu->per_cu->offset; + struct dwarf2_section_info *section = cu->per_cu->info_or_types_section; + struct create_dwo_info_table_data *data = datap; + struct dwo_file *dwo_file = data->dwo_file; + htab_t cu_htab = data->cu_htab; + void **slot; + struct attribute *attr; + struct dwo_unit *dwo_unit; + + attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_id, cu); + if (attr == NULL) + { + error (_("Dwarf Error: debug entry at offset 0x%x is missing" + " its dwo_id [in module %s]"), + offset.sect_off, dwo_file->name); + return; } - /* These are the only languages we know how to qualify names in. */ - if (name != NULL - && (cu->language == language_cplus || cu->language == language_java - || cu->language == language_fortran)) + dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit); + dwo_unit->dwo_file = dwo_file; + dwo_unit->signature = DW_UNSND (attr); + dwo_unit->info_or_types_section = section; + dwo_unit->offset = offset; + dwo_unit->length = cu->per_cu->length; + + slot = htab_find_slot (cu_htab, dwo_unit, INSERT); + gdb_assert (slot != NULL); + if (*slot != NULL) { - if (die_needs_namespace (die, cu)) - { - long length; - char *prefix; - struct ui_file *buf; + const struct dwo_unit *dup_dwo_unit = *slot; - prefix = determine_prefix (die, cu); - buf = mem_fileopen (); - if (*prefix != '\0') - { - char *prefixed_name = typename_concat (NULL, prefix, name, - physname, cu); + complaint (&symfile_complaints, + _("debug entry at offset 0x%x is duplicate to the entry at" + " offset 0x%x, dwo_id 0x%s [in module %s]"), + offset.sect_off, dup_dwo_unit->offset.sect_off, + phex (dwo_unit->signature, sizeof (dwo_unit->signature)), + dwo_file->name); + } + else + *slot = dwo_unit; - fputs_unfiltered (prefixed_name, buf); - xfree (prefixed_name); - } - else - fputs_unfiltered (name, buf); + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, " offset 0x%x, dwo_id 0x%s\n", + offset.sect_off, + phex (dwo_unit->signature, + sizeof (dwo_unit->signature))); +} - /* Template parameters may be specified in the DIE's DW_AT_name, or - as children with DW_TAG_template_type_param or - DW_TAG_value_type_param. If the latter, add them to the name - here. If the name already has template parameters, then - skip this step; some versions of GCC emit both, and - it is more efficient to use the pre-computed name. +/* Create a hash table to map DWO IDs to their CU entry in + .debug_info.dwo in DWO_FILE. + Note: This function processes DWO files only, not DWP files. */ - Something to keep in mind about this process: it is very - unlikely, or in some cases downright impossible, to produce - something that will match the mangled name of a function. - If the definition of the function has the same debug info, - we should be able to match up with it anyway. But fallbacks - using the minimal symbol, for instance to find a method - implemented in a stripped copy of libstdc++, will not work. - If we do not have debug info for the definition, we will have to - match them up some other way. +static htab_t +create_dwo_debug_info_hash_table (struct dwo_file *dwo_file) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_section_info *section = &dwo_file->sections.info; + bfd *abfd; + htab_t cu_htab; + gdb_byte *info_ptr, *end_ptr; + struct create_dwo_info_table_data create_dwo_info_table_data; - When we do name matching there is a related problem with function - templates; two instantiated function templates are allowed to - differ only by their return types, which we do not add here. */ + dwarf2_read_section (objfile, section); + info_ptr = section->buffer; - if (cu->language == language_cplus && strchr (name, '<') == NULL) - { - struct attribute *attr; - struct die_info *child; - int first = 1; + if (info_ptr == NULL) + return NULL; - die->building_fullname = 1; + /* We can't set abfd until now because the section may be empty or + not present, in which case section->asection will be NULL. */ + abfd = section->asection->owner; - for (child = die->child; child != NULL; child = child->sibling) - { - struct type *type; - long value; - gdb_byte *bytes; - struct dwarf2_locexpr_baton *baton; - struct value *v; + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "Reading .debug_info.dwo for %s:\n", + bfd_get_filename (abfd)); - if (child->tag != DW_TAG_template_type_param - && child->tag != DW_TAG_template_value_param) - continue; + cu_htab = allocate_dwo_unit_table (objfile); - if (first) - { - fputs_unfiltered ("<", buf); - first = 0; - } - else - fputs_unfiltered (", ", buf); + create_dwo_info_table_data.dwo_file = dwo_file; + create_dwo_info_table_data.cu_htab = cu_htab; - attr = dwarf2_attr (child, DW_AT_type, cu); - if (attr == NULL) - { - complaint (&symfile_complaints, - _("template parameter missing DW_AT_type")); - fputs_unfiltered ("UNKNOWN_TYPE", buf); - continue; - } - type = die_type (child, cu); + end_ptr = info_ptr + section->size; + while (info_ptr < end_ptr) + { + struct dwarf2_per_cu_data per_cu; - if (child->tag == DW_TAG_template_type_param) - { - c_print_type (type, "", buf, -1, 0); - continue; - } + memset (&per_cu, 0, sizeof (per_cu)); + per_cu.objfile = objfile; + per_cu.is_debug_types = 0; + per_cu.offset.sect_off = info_ptr - section->buffer; + per_cu.info_or_types_section = section; - attr = dwarf2_attr (child, DW_AT_const_value, cu); - if (attr == NULL) - { - complaint (&symfile_complaints, - _("template parameter missing " - "DW_AT_const_value")); - fputs_unfiltered ("UNKNOWN_VALUE", buf); - continue; - } + init_cutu_and_read_dies_no_follow (&per_cu, + &dwo_file->sections.abbrev, + dwo_file, + create_dwo_debug_info_hash_table_reader, + &create_dwo_info_table_data); - dwarf2_const_value_attr (attr, type, name, - &cu->comp_unit_obstack, cu, - &value, &bytes, &baton); + info_ptr += per_cu.length; + } - if (TYPE_NOSIGN (type)) - /* GDB prints characters as NUMBER 'CHAR'. If that's - changed, this can use value_print instead. */ - c_printchar (value, type, buf); - else - { - struct value_print_options opts; + return cu_htab; +} - if (baton != NULL) - v = dwarf2_evaluate_loc_desc (type, NULL, - baton->data, - baton->size, - baton->per_cu); - else if (bytes != NULL) - { - v = allocate_value (type); - memcpy (value_contents_writeable (v), bytes, - TYPE_LENGTH (type)); - } - else - v = value_from_longest (type, value); +/* DWP file .debug_{cu,tu}_index section format: + [ref: http://gcc.gnu.org/wiki/DebugFissionDWP] - /* Specify decimal so that we do not depend on - the radix. */ - get_formatted_print_options (&opts, 'd'); - opts.raw = 1; - value_print (v, buf, &opts); - release_value (v); - value_free (v); - } - } + Both index sections have the same format, and serve to map a 64-bit + signature to a set of section numbers. Each section begins with a header, + followed by a hash table of 64-bit signatures, a parallel table of 32-bit + indexes, and a pool of 32-bit section numbers. The index sections will be + aligned at 8-byte boundaries in the file. - die->building_fullname = 0; + The index section header contains two unsigned 32-bit values (using the + byte order of the application binary): - if (!first) - { - /* Close the argument list, with a space if necessary - (nested templates). */ - char last_char = '\0'; - ui_file_put (buf, do_ui_file_peek_last, &last_char); - if (last_char == '>') - fputs_unfiltered (" >", buf); - else - fputs_unfiltered (">", buf); - } - } + N, the number of compilation units or type units in the index + M, the number of slots in the hash table - /* For Java and C++ methods, append formal parameter type - information, if PHYSNAME. */ + (We assume that N and M will not exceed 2^32 - 1.) - if (physname && die->tag == DW_TAG_subprogram - && (cu->language == language_cplus - || cu->language == language_java)) - { - struct type *type = read_type_die (die, cu); + The size of the hash table, M, must be 2^k such that 2^k > 3*N/2. - c_type_print_args (type, buf, 1, cu->language); + The hash table begins at offset 8 in the section, and consists of an array + of M 64-bit slots. Each slot contains a 64-bit signature (using the byte + order of the application binary). Unused slots in the hash table are 0. + (We rely on the extreme unlikeliness of a signature being exactly 0.) - if (cu->language == language_java) - { - /* For java, we must append the return type to method - names. */ - if (die->tag == DW_TAG_subprogram) - java_print_type (TYPE_TARGET_TYPE (type), "", buf, - 0, 0); - } - else if (cu->language == language_cplus) - { - /* Assume that an artificial first parameter is - "this", but do not crash if it is not. RealView - marks unnamed (and thus unused) parameters as - artificial; there is no way to differentiate - the two cases. */ - if (TYPE_NFIELDS (type) > 0 - && TYPE_FIELD_ARTIFICIAL (type, 0) - && TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_PTR - && TYPE_CONST (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, - 0)))) - fputs_unfiltered (" const", buf); - } - } + The parallel table begins immediately after the hash table + (at offset 8 + 8 * M from the beginning of the section), and consists of an + array of 32-bit indexes (using the byte order of the application binary), + corresponding 1-1 with slots in the hash table. Each entry in the parallel + table contains a 32-bit index into the pool of section numbers. For unused + hash table slots, the corresponding entry in the parallel table will be 0. - name = ui_file_obsavestring (buf, &cu->objfile->objfile_obstack, - &length); - ui_file_delete (buf); + Given a 64-bit compilation unit signature or a type signature S, an entry + in the hash table is located as follows: + + 1) Calculate a primary hash H = S & MASK(k), where MASK(k) is a mask with + the low-order k bits all set to 1. + + 2) Calculate a secondary hash H' = (((S >> 32) & MASK(k)) | 1). + + 3) If the hash table entry at index H matches the signature, use that + entry. If the hash table entry at index H is unused (all zeroes), + terminate the search: the signature is not present in the table. + + 4) Let H = (H + H') modulo M. Repeat at Step 3. + + Because M > N and H' and M are relatively prime, the search is guaranteed + to stop at an unused slot or find the match. + + The pool of section numbers begins immediately following the hash table + (at offset 8 + 12 * M from the beginning of the section). The pool of + section numbers consists of an array of 32-bit words (using the byte order + of the application binary). Each item in the array is indexed starting + from 0. The hash table entry provides the index of the first section + number in the set. Additional section numbers in the set follow, and the + set is terminated by a 0 entry (section number 0 is not used in ELF). + + In each set of section numbers, the .debug_info.dwo or .debug_types.dwo + section must be the first entry in the set, and the .debug_abbrev.dwo must + be the second entry. Other members of the set may follow in any order. */ + +/* Create a hash table to map DWO IDs to their CU/TU entry in + .debug_{info,types}.dwo in DWP_FILE. + Returns NULL if there isn't one. + Note: This function processes DWP files only, not DWO files. */ + +static struct dwp_hash_table * +create_dwp_hash_table (struct dwp_file *dwp_file, int is_debug_types) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + bfd *dbfd = dwp_file->dbfd; + char *index_ptr, *index_end; + struct dwarf2_section_info *index; + uint32_t version, nr_units, nr_slots; + struct dwp_hash_table *htab; - if (cu->language == language_cplus) - { - char *cname - = dwarf2_canonicalize_name (name, cu, - &cu->objfile->objfile_obstack); + if (is_debug_types) + index = &dwp_file->sections.tu_index; + else + index = &dwp_file->sections.cu_index; - if (cname != NULL) - name = cname; - } - } - } + if (dwarf2_section_empty_p (index)) + return NULL; + dwarf2_read_section (objfile, index); - return name; -} + index_ptr = index->buffer; + index_end = index_ptr + index->size; -/* Return the fully qualified name of DIE, based on its DW_AT_name. - If scope qualifiers are appropriate they will be added. The result - will be allocated on the objfile_obstack, or NULL if the DIE does - not have a name. NAME may either be from a previous call to - dwarf2_name or NULL. + version = read_4_bytes (dbfd, index_ptr); + index_ptr += 8; /* Skip the unused word. */ + nr_units = read_4_bytes (dbfd, index_ptr); + index_ptr += 4; + nr_slots = read_4_bytes (dbfd, index_ptr); + index_ptr += 4; - The output string will be canonicalized (if C++/Java). */ + if (version != 1) + { + error (_("Dwarf Error: unsupported DWP file version (%u)" + " [in module %s]"), + version, dwp_file->name); + } + if (nr_slots != (nr_slots & -nr_slots)) + { + error (_("Dwarf Error: number of slots in DWP hash table (%u)" + " is not power of 2 [in module %s]"), + nr_slots, dwp_file->name); + } -static const char * -dwarf2_full_name (char *name, struct die_info *die, struct dwarf2_cu *cu) -{ - return dwarf2_compute_name (name, die, cu, 0); + htab = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwp_hash_table); + htab->nr_units = nr_units; + htab->nr_slots = nr_slots; + htab->hash_table = index_ptr; + htab->unit_table = htab->hash_table + sizeof (uint64_t) * nr_slots; + htab->section_pool = htab->unit_table + sizeof (uint32_t) * nr_slots; + + return htab; } -/* Construct a physname for the given DIE in CU. NAME may either be - from a previous call to dwarf2_name or NULL. The result will be - allocated on the objfile_objstack or NULL if the DIE does not have a - name. +/* Update SECTIONS with the data from SECTP. - The output string will be canonicalized (if C++/Java). */ + This function is like the other "locate" section routines that are + passed to bfd_map_over_sections, but in this context the sections to + read comes from the DWP hash table, not the full ELF section table. -static const char * -dwarf2_physname (char *name, struct die_info *die, struct dwarf2_cu *cu) + The result is non-zero for success, or zero if an error was found. */ + +static int +locate_virtual_dwo_sections (asection *sectp, + struct virtual_dwo_sections *sections) { - struct attribute *attr; - const char *retval, *mangled = NULL, *canon = NULL; - struct cleanup *back_to; - int need_copy = 1; + const struct dwop_section_names *names = &dwop_section_names; - /* In this case dwarf2_compute_name is just a shortcut not building anything - on its own. */ - if (!die_needs_namespace (die, cu)) - return dwarf2_compute_name (name, die, cu, 1); + if (section_is_p (sectp->name, &names->abbrev_dwo)) + { + /* There can be only one. */ + if (sections->abbrev.asection != NULL) + return 0; + sections->abbrev.asection = sectp; + sections->abbrev.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->info_dwo) + || section_is_p (sectp->name, &names->types_dwo)) + { + /* There can be only one. */ + if (sections->info_or_types.asection != NULL) + return 0; + sections->info_or_types.asection = sectp; + sections->info_or_types.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->line_dwo)) + { + /* There can be only one. */ + if (sections->line.asection != NULL) + return 0; + sections->line.asection = sectp; + sections->line.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->loc_dwo)) + { + /* There can be only one. */ + if (sections->loc.asection != NULL) + return 0; + sections->loc.asection = sectp; + sections->loc.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->macinfo_dwo)) + { + /* There can be only one. */ + if (sections->macinfo.asection != NULL) + return 0; + sections->macinfo.asection = sectp; + sections->macinfo.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->macro_dwo)) + { + /* There can be only one. */ + if (sections->macro.asection != NULL) + return 0; + sections->macro.asection = sectp; + sections->macro.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->str_offsets_dwo)) + { + /* There can be only one. */ + if (sections->str_offsets.asection != NULL) + return 0; + sections->str_offsets.asection = sectp; + sections->str_offsets.size = bfd_get_section_size (sectp); + } + else + { + /* No other kind of section is valid. */ + return 0; + } - back_to = make_cleanup (null_cleanup, NULL); + return 1; +} - attr = dwarf2_attr (die, DW_AT_linkage_name, cu); - if (!attr) - attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); +/* Create a dwo_unit object for the DWO with signature SIGNATURE. + HTAB is the hash table from the DWP file. + SECTION_INDEX is the index of the DWO in HTAB. */ + +static struct dwo_unit * +create_dwo_in_dwp (struct dwp_file *dwp_file, + const struct dwp_hash_table *htab, + uint32_t section_index, + ULONGEST signature, int is_debug_types) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + bfd *dbfd = dwp_file->dbfd; + const char *kind = is_debug_types ? "TU" : "CU"; + struct dwo_file *dwo_file; + struct dwo_unit *dwo_unit; + struct virtual_dwo_sections sections; + void **dwo_file_slot; + char *virtual_dwo_name; + struct dwarf2_section_info *cutu; + struct cleanup *cleanups; + int i; - /* DW_AT_linkage_name is missing in some cases - depend on what GDB - has computed. */ - if (attr && DW_STRING (attr)) + if (dwarf2_read_debug) { - char *demangled; + fprintf_unfiltered (gdb_stdlog, "Reading %s %u/0x%s in DWP file: %s\n", + kind, + section_index, phex (signature, sizeof (signature)), + dwp_file->name); + } - mangled = DW_STRING (attr); + /* Fetch the sections of this DWO. + Put a limit on the number of sections we look for so that bad data + doesn't cause us to loop forever. */ - /* Use DMGL_RET_DROP for C++ template functions to suppress their return - type. It is easier for GDB users to search for such functions as - `name(params)' than `long name(params)'. In such case the minimal - symbol names do not match the full symbol names but for template - functions there is never a need to look up their definition from their - declaration so the only disadvantage remains the minimal symbol - variant `long name(params)' does not have the proper inferior type. - */ +#define MAX_NR_DWO_SECTIONS \ + (1 /* .debug_info or .debug_types */ \ + + 1 /* .debug_abbrev */ \ + + 1 /* .debug_line */ \ + + 1 /* .debug_loc */ \ + + 1 /* .debug_str_offsets */ \ + + 1 /* .debug_macro */ \ + + 1 /* .debug_macinfo */ \ + + 1 /* trailing zero */) - demangled = cplus_demangle (mangled, (DMGL_PARAMS | DMGL_ANSI - | (cu->language == language_java - ? DMGL_JAVA | DMGL_RET_POSTFIX - : DMGL_RET_DROP))); - if (demangled) + memset (§ions, 0, sizeof (sections)); + cleanups = make_cleanup (null_cleanup, 0); + + for (i = 0; i < MAX_NR_DWO_SECTIONS; ++i) + { + asection *sectp; + uint32_t section_nr = + read_4_bytes (dbfd, + htab->section_pool + + (section_index + i) * sizeof (uint32_t)); + + if (section_nr == 0) + break; + if (section_nr >= dwp_file->num_sections) { - make_cleanup (xfree, demangled); - canon = demangled; + error (_("Dwarf Error: bad DWP hash table, section number too large" + " [in module %s]"), + dwp_file->name); } - else + + sectp = dwp_file->elf_sections[section_nr]; + if (! locate_virtual_dwo_sections (sectp, §ions)) { - canon = mangled; - need_copy = 0; + error (_("Dwarf Error: bad DWP hash table, invalid section found" + " [in module %s]"), + dwp_file->name); } } - if (canon == NULL || check_physname) + if (i < 2 + || sections.info_or_types.asection == NULL + || sections.abbrev.asection == NULL) { - const char *physname = dwarf2_compute_name (name, die, cu, 1); - - if (canon != NULL && strcmp (physname, canon) != 0) - { - /* It may not mean a bug in GDB. The compiler could also - compute DW_AT_linkage_name incorrectly. But in such case - GDB would need to be bug-to-bug compatible. */ + error (_("Dwarf Error: bad DWP hash table, missing DWO sections" + " [in module %s]"), + dwp_file->name); + } + if (i == MAX_NR_DWO_SECTIONS) + { + error (_("Dwarf Error: bad DWP hash table, too many DWO sections" + " [in module %s]"), + dwp_file->name); + } - complaint (&symfile_complaints, - _("Computed physname <%s> does not match demangled <%s> " - "(from linkage <%s>) - DIE at 0x%x [in module %s]"), - physname, canon, mangled, die->offset, cu->objfile->name); + /* It's easier for the rest of the code if we fake a struct dwo_file and + have dwo_unit "live" in that. At least for now. - /* Prefer DW_AT_linkage_name (in the CANON form) - when it - is available here - over computed PHYSNAME. It is safer - against both buggy GDB and buggy compilers. */ + The DWP file can be made up of a random collection of CUs and TUs. + However, for each CU + set of TUs that came from the same original DWO + file, we want to combine them back into a virtual DWO file to save space + (fewer struct dwo_file objects to allocated). Remember that for really + large apps there can be on the order of 8K CUs and 200K TUs, or more. */ - retval = canon; - } - else + virtual_dwo_name = + xstrprintf ("virtual-dwo/%d-%d-%d-%d", + sections.abbrev.asection ? sections.abbrev.asection->id : 0, + sections.line.asection ? sections.line.asection->id : 0, + sections.loc.asection ? sections.loc.asection->id : 0, + (sections.str_offsets.asection + ? sections.str_offsets.asection->id + : 0)); + make_cleanup (xfree, virtual_dwo_name); + /* Can we use an existing virtual DWO file? */ + dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name); + /* Create one if necessary. */ + if (*dwo_file_slot == NULL) + { + if (dwarf2_read_debug) { - retval = physname; - need_copy = 0; + fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n", + virtual_dwo_name); } + dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file); + dwo_file->name = obstack_copy0 (&objfile->objfile_obstack, + virtual_dwo_name, + strlen (virtual_dwo_name)); + dwo_file->sections.abbrev = sections.abbrev; + dwo_file->sections.line = sections.line; + dwo_file->sections.loc = sections.loc; + dwo_file->sections.macinfo = sections.macinfo; + dwo_file->sections.macro = sections.macro; + dwo_file->sections.str_offsets = sections.str_offsets; + /* The "str" section is global to the entire DWP file. */ + dwo_file->sections.str = dwp_file->sections.str; + /* The info or types section is assigned later to dwo_unit, + there's no need to record it in dwo_file. + Also, we can't simply record type sections in dwo_file because + we record a pointer into the vector in dwo_unit. As we collect more + types we'll grow the vector and eventually have to reallocate space + for it, invalidating all the pointers into the current copy. */ + *dwo_file_slot = dwo_file; } else - retval = canon; + { + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n", + virtual_dwo_name); + } + dwo_file = *dwo_file_slot; + } + do_cleanups (cleanups); - if (need_copy) - retval = obsavestring (retval, strlen (retval), - &cu->objfile->objfile_obstack); + dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit); + dwo_unit->dwo_file = dwo_file; + dwo_unit->signature = signature; + dwo_unit->info_or_types_section = + obstack_alloc (&objfile->objfile_obstack, + sizeof (struct dwarf2_section_info)); + *dwo_unit->info_or_types_section = sections.info_or_types; + /* offset, length, type_offset_in_tu are set later. */ - do_cleanups (back_to); - return retval; + return dwo_unit; } -/* Read the import statement specified by the given die and record it. */ +/* Lookup the DWO with SIGNATURE in DWP_FILE. */ -static void -read_import_statement (struct die_info *die, struct dwarf2_cu *cu) +static struct dwo_unit * +lookup_dwo_in_dwp (struct dwp_file *dwp_file, + const struct dwp_hash_table *htab, + ULONGEST signature, int is_debug_types) { - struct attribute *import_attr; - struct die_info *imported_die, *child_die; - struct dwarf2_cu *imported_cu; - const char *imported_name; - const char *imported_name_prefix; - const char *canonical_name; - const char *import_alias; - const char *imported_declaration = NULL; - const char *import_prefix; - VEC (const_char_ptr) *excludes = NULL; - struct cleanup *cleanups; + bfd *dbfd = dwp_file->dbfd; + uint32_t mask = htab->nr_slots - 1; + uint32_t hash = signature & mask; + uint32_t hash2 = ((signature >> 32) & mask) | 1; + unsigned int i; + void **slot; + struct dwo_unit find_dwo_cu, *dwo_cu; - char *temp; + memset (&find_dwo_cu, 0, sizeof (find_dwo_cu)); + find_dwo_cu.signature = signature; + slot = htab_find_slot (dwp_file->loaded_cutus, &find_dwo_cu, INSERT); - 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; - } + if (*slot != NULL) + return *slot; - imported_cu = cu; - imported_die = follow_die_ref_or_sig (die, import_attr, &imported_cu); - imported_name = dwarf2_name (imported_die, imported_cu); - if (imported_name == NULL) + /* Use a for loop so that we don't loop forever on bad debug info. */ + for (i = 0; i < htab->nr_slots; ++i) { - /* GCC bug: https://bugzilla.redhat.com/show_bug.cgi?id=506524 - - The import in the following code: - namespace A - { - typedef int B; - } + ULONGEST signature_in_table; - int main () - { - using A::B; - B b; - return b; - } - - ... - <2><51>: Abbrev Number: 3 (DW_TAG_imported_declaration) - <52> DW_AT_decl_file : 1 - <53> DW_AT_decl_line : 6 - <54> DW_AT_import : <0x75> - <2><58>: Abbrev Number: 4 (DW_TAG_typedef) - <59> DW_AT_name : B - <5b> DW_AT_decl_file : 1 - <5c> DW_AT_decl_line : 2 - <5d> DW_AT_type : <0x6e> - ... - <1><75>: Abbrev Number: 7 (DW_TAG_base_type) - <76> DW_AT_byte_size : 4 - <77> DW_AT_encoding : 5 (signed) + signature_in_table = + read_8_bytes (dbfd, htab->hash_table + hash * sizeof (uint64_t)); + if (signature_in_table == signature) + { + uint32_t section_index = + read_4_bytes (dbfd, htab->unit_table + hash * sizeof (uint32_t)); - imports the wrong die ( 0x75 instead of 0x58 ). - This case will be ignored until the gcc bug is fixed. */ - return; + *slot = create_dwo_in_dwp (dwp_file, htab, section_index, + signature, is_debug_types); + return *slot; + } + if (signature_in_table == 0) + return NULL; + hash = (hash + hash2) & mask; } - /* Figure out the local name after import. */ - import_alias = dwarf2_name (die, cu); + error (_("Dwarf Error: bad DWP hash table, lookup didn't terminate" + " [in module %s]"), + dwp_file->name); +} - /* Figure out where the statement is being imported to. */ - import_prefix = determine_prefix (die, cu); +/* Subroutine of open_dwop_file to simplify it. + Open the file specified by FILE_NAME and hand it off to BFD for + preliminary analysis. Return a newly initialized bfd *, which + includes a canonicalized copy of FILE_NAME. + If IS_DWP is TRUE, we're opening a DWP file, otherwise a DWO file. + In case of trouble, return NULL. + NOTE: This function is derived from symfile_bfd_open. */ - /* 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, imported_cu); +static bfd * +try_open_dwop_file (const char *file_name, int is_dwp) +{ + bfd *sym_bfd; + int desc, flags; + char *absolute_name; - if (imported_die->tag != DW_TAG_namespace - && imported_die->tag != DW_TAG_module) + flags = OPF_TRY_CWD_FIRST; + if (is_dwp) + flags |= OPF_SEARCH_IN_PATH; + desc = openp (debug_file_directory, flags, file_name, + O_RDONLY | O_BINARY, &absolute_name); + if (desc < 0) + return NULL; + + sym_bfd = gdb_bfd_open (absolute_name, gnutarget, desc); + if (!sym_bfd) { - imported_declaration = imported_name; - canonical_name = imported_name_prefix; + xfree (absolute_name); + return NULL; } - else if (strlen (imported_name_prefix) > 0) + xfree (absolute_name); + bfd_set_cacheable (sym_bfd, 1); + + if (!bfd_check_format (sym_bfd, bfd_object)) { - temp = alloca (strlen (imported_name_prefix) - + 2 + strlen (imported_name) + 1); - strcpy (temp, imported_name_prefix); - strcat (temp, "::"); - strcat (temp, imported_name); - canonical_name = temp; + gdb_bfd_unref (sym_bfd); /* This also closes desc. */ + return NULL; } - else - canonical_name = imported_name; - cleanups = make_cleanup (VEC_cleanup (const_char_ptr), &excludes); + return sym_bfd; +} - if (die->tag == DW_TAG_imported_module && cu->language == language_fortran) - for (child_die = die->child; child_die && child_die->tag; - child_die = sibling_die (child_die)) - { - /* DWARF-4: A Fortran use statement with a “rename list” may be - represented by an imported module entry with an import attribute - referring to the module and owned entries corresponding to those - entities that are renamed as part of being imported. */ +/* Try to open DWO/DWP file FILE_NAME. + COMP_DIR is the DW_AT_comp_dir attribute. + If IS_DWP is TRUE, we're opening a DWP file, otherwise a DWO file. + The result is the bfd handle of the file. + If there is a problem finding or opening the file, return NULL. + Upon success, the canonicalized path of the file is stored in the bfd, + same as symfile_bfd_open. */ - if (child_die->tag != DW_TAG_imported_declaration) - { - complaint (&symfile_complaints, - _("child DW_TAG_imported_declaration expected " - "- DIE at 0x%x [in module %s]"), - child_die->offset, cu->objfile->name); - continue; - } +static bfd * +open_dwop_file (const char *file_name, const char *comp_dir, int is_dwp) +{ + bfd *abfd; - import_attr = dwarf2_attr (child_die, DW_AT_import, cu); - if (import_attr == NULL) - { - complaint (&symfile_complaints, _("Tag '%s' has no DW_AT_import"), - dwarf_tag_name (child_die->tag)); - continue; - } + if (IS_ABSOLUTE_PATH (file_name)) + return try_open_dwop_file (file_name, is_dwp); - imported_cu = cu; - imported_die = follow_die_ref_or_sig (child_die, import_attr, - &imported_cu); - imported_name = dwarf2_name (imported_die, imported_cu); - if (imported_name == NULL) - { - complaint (&symfile_complaints, - _("child DW_TAG_imported_declaration has unknown " - "imported name - DIE at 0x%x [in module %s]"), - child_die->offset, cu->objfile->name); - continue; - } + /* Before trying the search path, try DWO_NAME in COMP_DIR. */ - VEC_safe_push (const_char_ptr, excludes, imported_name); + if (comp_dir != NULL) + { + char *path_to_try = concat (comp_dir, SLASH_STRING, file_name, NULL); + + /* NOTE: If comp_dir is a relative path, this will also try the + search path, which seems useful. */ + abfd = try_open_dwop_file (path_to_try, is_dwp); + xfree (path_to_try); + if (abfd != NULL) + return abfd; + } - process_die (child_die, cu); - } + /* That didn't work, try debug-file-directory, which, despite its name, + is a list of paths. */ - cp_add_using_directive (import_prefix, - canonical_name, - import_alias, - imported_declaration, - excludes, - &cu->objfile->objfile_obstack); + if (*debug_file_directory == '\0') + return NULL; - do_cleanups (cleanups); + return try_open_dwop_file (file_name, is_dwp); } +/* This function is mapped across the sections and remembers the offset and + size of each of the DWO debugging sections we are interested in. */ + static void -initialize_cu_func_list (struct dwarf2_cu *cu) +dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp, void *dwo_sections_ptr) { - cu->first_fn = cu->last_fn = cu->cached_fn = NULL; + struct dwo_sections *dwo_sections = dwo_sections_ptr; + const struct dwop_section_names *names = &dwop_section_names; + + if (section_is_p (sectp->name, &names->abbrev_dwo)) + { + dwo_sections->abbrev.asection = sectp; + dwo_sections->abbrev.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->info_dwo)) + { + dwo_sections->info.asection = sectp; + dwo_sections->info.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->line_dwo)) + { + dwo_sections->line.asection = sectp; + dwo_sections->line.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->loc_dwo)) + { + dwo_sections->loc.asection = sectp; + dwo_sections->loc.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->macinfo_dwo)) + { + dwo_sections->macinfo.asection = sectp; + dwo_sections->macinfo.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->macro_dwo)) + { + dwo_sections->macro.asection = sectp; + dwo_sections->macro.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->str_dwo)) + { + dwo_sections->str.asection = sectp; + dwo_sections->str.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->str_offsets_dwo)) + { + dwo_sections->str_offsets.asection = sectp; + dwo_sections->str_offsets.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->types_dwo)) + { + struct dwarf2_section_info type_section; + + memset (&type_section, 0, sizeof (type_section)); + type_section.asection = sectp; + type_section.size = bfd_get_section_size (sectp); + VEC_safe_push (dwarf2_section_info_def, dwo_sections->types, + &type_section); + } } -/* Cleanup function for read_file_scope. */ +/* Initialize the use of the DWO file specified by DWO_NAME. + The result is NULL if DWO_NAME can't be found. */ -static void -free_cu_line_header (void *arg) +static struct dwo_file * +open_and_init_dwo_file (const char *dwo_name, const char *comp_dir) { - struct dwarf2_cu *cu = arg; + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwo_file *dwo_file; + bfd *dbfd; + struct cleanup *cleanups; - free_line_header (cu->line_header); - cu->line_header = NULL; + dbfd = open_dwop_file (dwo_name, comp_dir, 0); + if (dbfd == NULL) + { + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "DWO file not found: %s\n", dwo_name); + return NULL; + } + dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file); + dwo_file->name = obstack_copy0 (&objfile->objfile_obstack, + dwo_name, strlen (dwo_name)); + dwo_file->dbfd = dbfd; + + cleanups = make_cleanup (free_dwo_file_cleanup, dwo_file); + + bfd_map_over_sections (dbfd, dwarf2_locate_dwo_sections, &dwo_file->sections); + + dwo_file->cus = create_dwo_debug_info_hash_table (dwo_file); + + dwo_file->tus = create_debug_types_hash_table (dwo_file, + dwo_file->sections.types); + + discard_cleanups (cleanups); + + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "DWO file found: %s\n", dwo_name); + + return dwo_file; } +/* This function is mapped across the sections and remembers the offset and + size of each of the DWP debugging sections we are interested in. */ + static void -find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu, - char **name, char **comp_dir) +dwarf2_locate_dwp_sections (bfd *abfd, asection *sectp, void *dwp_file_ptr) { - struct attribute *attr; + struct dwp_file *dwp_file = dwp_file_ptr; + const struct dwop_section_names *names = &dwop_section_names; + unsigned int elf_section_nr = elf_section_data (sectp)->this_idx; - *name = NULL; - *comp_dir = NULL; + /* Record the ELF section number for later lookup: this is what the + .debug_cu_index,.debug_tu_index tables use. */ + gdb_assert (elf_section_nr < dwp_file->num_sections); + dwp_file->elf_sections[elf_section_nr] = sectp; - /* Find the filename. Do not use dwarf2_name here, since the filename - is not a source language identifier. */ - attr = dwarf2_attr (die, DW_AT_name, cu); - if (attr) + /* Look for specific sections that we need. */ + if (section_is_p (sectp->name, &names->str_dwo)) { - *name = DW_STRING (attr); + dwp_file->sections.str.asection = sectp; + dwp_file->sections.str.size = bfd_get_section_size (sectp); } - - attr = dwarf2_attr (die, DW_AT_comp_dir, cu); - if (attr) - *comp_dir = DW_STRING (attr); - else if (*name != NULL && IS_ABSOLUTE_PATH (*name)) + else if (section_is_p (sectp->name, &names->cu_index)) { - *comp_dir = ldirname (*name); - if (*comp_dir != NULL) - make_cleanup (xfree, *comp_dir); + dwp_file->sections.cu_index.asection = sectp; + dwp_file->sections.cu_index.size = bfd_get_section_size (sectp); } - if (*comp_dir != NULL) + else if (section_is_p (sectp->name, &names->tu_index)) { - /* Irix 6.2 native cc prepends .: to the compilation - directory, get rid of it. */ - char *cp = strchr (*comp_dir, ':'); - - if (cp && cp != *comp_dir && cp[-1] == '.' && cp[1] == '/') - *comp_dir = cp + 1; + dwp_file->sections.tu_index.asection = sectp; + dwp_file->sections.tu_index.size = bfd_get_section_size (sectp); } +} - if (*name == NULL) - *name = ""; +/* Hash function for dwp_file loaded CUs/TUs. */ + +static hashval_t +hash_dwp_loaded_cutus (const void *item) +{ + const struct dwo_unit *dwo_unit = item; + + /* This drops the top 32 bits of the signature, but is ok for a hash. */ + return dwo_unit->signature; } -/* Handle DW_AT_stmt_list for a compilation unit or type unit. - DIE is the DW_TAG_compile_unit or DW_TAG_type_unit die for CU. - COMP_DIR is the compilation directory. - WANT_LINE_INFO is non-zero if the pc/line-number mapping is needed. */ +/* Equality function for dwp_file loaded CUs/TUs. */ -static void -handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu, - const char *comp_dir, int want_line_info) +static int +eq_dwp_loaded_cutus (const void *a, const void *b) { - struct attribute *attr; - struct objfile *objfile = cu->objfile; - bfd *abfd = objfile->obfd; + const struct dwo_unit *dua = a; + const struct dwo_unit *dub = b; - attr = dwarf2_attr (die, DW_AT_stmt_list, cu); - if (attr) - { - unsigned int line_offset = DW_UNSND (attr); - struct line_header *line_header - = dwarf_decode_line_header (line_offset, abfd, cu); + return dua->signature == dub->signature; +} - if (line_header) - { - cu->line_header = line_header; - make_cleanup (free_cu_line_header, cu); - dwarf_decode_lines (line_header, comp_dir, cu, NULL, want_line_info); - } - } +/* Allocate a hash table for dwp_file loaded CUs/TUs. */ + +static htab_t +allocate_dwp_loaded_cutus_table (struct objfile *objfile) +{ + return htab_create_alloc_ex (3, + hash_dwp_loaded_cutus, + eq_dwp_loaded_cutus, + NULL, + &objfile->objfile_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); } -/* Process DW_TAG_compile_unit. */ +/* Initialize the use of the DWP file for the current objfile. + By convention the name of the DWP file is ${objfile}.dwp. + The result is NULL if it can't be found. */ -static void -read_file_scope (struct die_info *die, struct dwarf2_cu *cu) +static struct dwp_file * +open_and_init_dwp_file (const char *comp_dir) { - struct objfile *objfile = cu->objfile; - struct cleanup *back_to = make_cleanup (null_cleanup, 0); - CORE_ADDR lowpc = ((CORE_ADDR) -1); - CORE_ADDR highpc = ((CORE_ADDR) 0); - struct attribute *attr; - char *name = NULL; - char *comp_dir = NULL; - struct die_info *child_die; - bfd *abfd = objfile->obfd; - CORE_ADDR baseaddr; + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwp_file *dwp_file; + char *dwp_name; + bfd *dbfd; + struct cleanup *cleanups; - baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + dwp_name = xstrprintf ("%s.dwp", dwarf2_per_objfile->objfile->name); + cleanups = make_cleanup (xfree, dwp_name); - get_scope_pc_bounds (die, &lowpc, &highpc, cu); + dbfd = open_dwop_file (dwp_name, comp_dir, 1); + if (dbfd == NULL) + { + if (dwarf2_read_debug) + fprintf_unfiltered (gdb_stdlog, "DWP file not found: %s\n", dwp_name); + do_cleanups (cleanups); + return NULL; + } + dwp_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwp_file); + dwp_file->name = obstack_copy0 (&objfile->objfile_obstack, + dwp_name, strlen (dwp_name)); + dwp_file->dbfd = dbfd; + do_cleanups (cleanups); - /* If we didn't find a lowpc, set it to highpc to avoid complaints - from finish_block. */ - if (lowpc == ((CORE_ADDR) -1)) - lowpc = highpc; - lowpc += baseaddr; - highpc += baseaddr; + /* +1: section 0 is unused */ + dwp_file->num_sections = bfd_count_sections (dbfd) + 1; + dwp_file->elf_sections = + OBSTACK_CALLOC (&objfile->objfile_obstack, + dwp_file->num_sections, asection *); - find_file_and_directory (die, cu, &name, &comp_dir); + bfd_map_over_sections (dbfd, dwarf2_locate_dwp_sections, dwp_file); - attr = dwarf2_attr (die, DW_AT_language, cu); - if (attr) + dwp_file->cus = create_dwp_hash_table (dwp_file, 0); + + dwp_file->tus = create_dwp_hash_table (dwp_file, 1); + + dwp_file->loaded_cutus = allocate_dwp_loaded_cutus_table (objfile); + + if (dwarf2_read_debug) { - set_cu_language (DW_UNSND (attr), cu); + fprintf_unfiltered (gdb_stdlog, "DWP file found: %s\n", dwp_file->name); + fprintf_unfiltered (gdb_stdlog, + " %u CUs, %u TUs\n", + dwp_file->cus ? dwp_file->cus->nr_units : 0, + dwp_file->tus ? dwp_file->tus->nr_units : 0); } - attr = dwarf2_attr (die, DW_AT_producer, cu); - if (attr) - cu->producer = DW_STRING (attr); + return dwp_file; +} - /* The XLCL doesn't generate DW_LANG_OpenCL because this attribute is not - standardised yet. As a workaround for the language detection we fall - back to the DW_AT_producer string. */ - if (cu->producer && strstr (cu->producer, "IBM XL C for OpenCL") != NULL) - cu->language = language_opencl; +/* Subroutine of lookup_dwo_comp_unit, lookup_dwo_type_unit. + Look up the CU/TU with signature SIGNATURE, either in DWO file DWO_NAME + or in the DWP file for the objfile, referenced by THIS_UNIT. + If non-NULL, comp_dir is the DW_AT_comp_dir attribute. + IS_DEBUG_TYPES is non-zero if reading a TU, otherwise read a CU. - /* We assume that we're processing GCC output. */ - processing_gcc_compilation = 2; + This is called, for example, when wanting to read a variable with a + complex location. Therefore we don't want to do file i/o for every call. + Therefore we don't want to look for a DWO file on every call. + Therefore we first see if we've already seen SIGNATURE in a DWP file, + then we check if we've already seen DWO_NAME, and only THEN do we check + for a DWO file. - processing_has_namespace_info = 0; + The result is a pointer to the dwo_unit object or NULL if we didn't find it + (dwo_id mismatch or couldn't find the DWO/DWP file). */ - start_symtab (name, comp_dir, lowpc); - record_debugformat ("DWARF 2"); - record_producer (cu->producer); +static struct dwo_unit * +lookup_dwo_cutu (struct dwarf2_per_cu_data *this_unit, + const char *dwo_name, const char *comp_dir, + ULONGEST signature, int is_debug_types) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + const char *kind = is_debug_types ? "TU" : "CU"; + void **dwo_file_slot; + struct dwo_file *dwo_file; + struct dwp_file *dwp_file; - initialize_cu_func_list (cu); + /* Have we already read SIGNATURE from a DWP file? */ - /* Decode line number information if present. We do this before - processing child DIEs, so that the line header table is available - for DW_AT_decl_file. */ - handle_DW_AT_stmt_list (die, cu, comp_dir, 1); + if (! dwarf2_per_objfile->dwp_checked) + { + dwarf2_per_objfile->dwp_file = open_and_init_dwp_file (comp_dir); + dwarf2_per_objfile->dwp_checked = 1; + } + dwp_file = dwarf2_per_objfile->dwp_file; - /* Process all dies in compilation unit. */ - if (die->child != NULL) + if (dwp_file != NULL) { - child_die = die->child; - while (child_die && child_die->tag) + const struct dwp_hash_table *dwp_htab = + is_debug_types ? dwp_file->tus : dwp_file->cus; + + if (dwp_htab != NULL) { - process_die (child_die, cu); - child_die = sibling_die (child_die); + struct dwo_unit *dwo_cutu = + lookup_dwo_in_dwp (dwp_file, dwp_htab, signature, is_debug_types); + + if (dwo_cutu != NULL) + { + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Virtual DWO %s %s found: @%s\n", + kind, hex_string (signature), + host_address_to_string (dwo_cutu)); + } + return dwo_cutu; + } } } - /* Decode macro information, if present. Dwarf 2 macro information - refers to information in the line number info statement program - header, so we can only read it if we've read the header - successfully. */ - attr = dwarf2_attr (die, DW_AT_GNU_macros, cu); - if (attr && cu->line_header) - { - if (dwarf2_attr (die, DW_AT_macro_info, cu)) - complaint (&symfile_complaints, - _("CU refers to both DW_AT_GNU_macros and DW_AT_macro_info")); + /* Have we already seen DWO_NAME? */ - dwarf_decode_macros (cu->line_header, DW_UNSND (attr), - comp_dir, abfd, cu, - &dwarf2_per_objfile->macro, 1); + dwo_file_slot = lookup_dwo_file_slot (dwo_name); + if (*dwo_file_slot == NULL) + { + /* Read in the file and build a table of the DWOs it contains. */ + *dwo_file_slot = open_and_init_dwo_file (dwo_name, comp_dir); } - else + /* NOTE: This will be NULL if unable to open the file. */ + dwo_file = *dwo_file_slot; + + if (dwo_file != NULL) { - attr = dwarf2_attr (die, DW_AT_macro_info, cu); - if (attr && cu->line_header) + htab_t htab = is_debug_types ? dwo_file->tus : dwo_file->cus; + + if (htab != NULL) { - unsigned int macro_offset = DW_UNSND (attr); + struct dwo_unit find_dwo_cutu, *dwo_cutu; + + memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu)); + find_dwo_cutu.signature = signature; + dwo_cutu = htab_find (htab, &find_dwo_cutu); - dwarf_decode_macros (cu->line_header, macro_offset, - comp_dir, abfd, cu, - &dwarf2_per_objfile->macinfo, 0); + if (dwo_cutu != NULL) + { + if (dwarf2_read_debug) + { + fprintf_unfiltered (gdb_stdlog, "DWO %s %s(%s) found: @%s\n", + kind, dwo_name, hex_string (signature), + host_address_to_string (dwo_cutu)); + } + return dwo_cutu; + } } } - do_cleanups (back_to); -} - -/* Process DW_TAG_type_unit. - For TUs we want to skip the first top level sibling if it's not the - actual type being defined by this TU. In this case the first top - level sibling is there to provide context only. */ - -static void -read_type_unit_scope (struct die_info *die, struct dwarf2_cu *cu) -{ - struct objfile *objfile = cu->objfile; - struct cleanup *back_to = make_cleanup (null_cleanup, 0); - CORE_ADDR lowpc; - struct attribute *attr; - char *name = NULL; - char *comp_dir = NULL; - struct die_info *child_die; - bfd *abfd = objfile->obfd; - - /* start_symtab needs a low pc, but we don't really have one. - Do what read_file_scope would do in the absence of such info. */ - lowpc = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - /* Find the filename. Do not use dwarf2_name here, since the filename - is not a source language identifier. */ - attr = dwarf2_attr (die, DW_AT_name, cu); - if (attr) - name = DW_STRING (attr); + /* We didn't find it. This could mean a dwo_id mismatch, or + someone deleted the DWO/DWP file, or the search path isn't set up + correctly to find the file. */ - attr = dwarf2_attr (die, DW_AT_comp_dir, cu); - if (attr) - comp_dir = DW_STRING (attr); - else if (name != NULL && IS_ABSOLUTE_PATH (name)) + if (dwarf2_read_debug) { - comp_dir = ldirname (name); - if (comp_dir != NULL) - make_cleanup (xfree, comp_dir); + fprintf_unfiltered (gdb_stdlog, "DWO %s %s(%s) not found\n", + kind, dwo_name, hex_string (signature)); } - if (name == NULL) - name = ""; + complaint (&symfile_complaints, + _("Could not find DWO CU referenced by CU at offset 0x%x" + " [in module %s]"), + this_unit->offset.sect_off, objfile->name); + return NULL; +} - attr = dwarf2_attr (die, DW_AT_language, cu); - if (attr) - set_cu_language (DW_UNSND (attr), cu); +/* Lookup the DWO CU DWO_NAME/SIGNATURE referenced from THIS_CU. + See lookup_dwo_cutu_unit for details. */ - /* This isn't technically needed today. It is done for symmetry - with read_file_scope. */ - attr = dwarf2_attr (die, DW_AT_producer, cu); - if (attr) - cu->producer = DW_STRING (attr); +static struct dwo_unit * +lookup_dwo_comp_unit (struct dwarf2_per_cu_data *this_cu, + const char *dwo_name, const char *comp_dir, + ULONGEST signature) +{ + return lookup_dwo_cutu (this_cu, dwo_name, comp_dir, signature, 0); +} - /* We assume that we're processing GCC output. */ - processing_gcc_compilation = 2; +/* Lookup the DWO TU DWO_NAME/SIGNATURE referenced from THIS_TU. + See lookup_dwo_cutu_unit for details. */ - processing_has_namespace_info = 0; +static struct dwo_unit * +lookup_dwo_type_unit (struct signatured_type *this_tu, + const char *dwo_name, const char *comp_dir) +{ + return lookup_dwo_cutu (&this_tu->per_cu, dwo_name, comp_dir, this_tu->signature, 1); +} - start_symtab (name, comp_dir, lowpc); - record_debugformat ("DWARF 2"); - record_producer (cu->producer); +/* Free all resources associated with DWO_FILE. + Close the DWO file and munmap the sections. + All memory should be on the objfile obstack. */ - /* Decode line number information if present. We do this before - processing child DIEs, so that the line header table is available - for DW_AT_decl_file. - We don't need the pc/line-number mapping for type units. */ - handle_DW_AT_stmt_list (die, cu, comp_dir, 0); +static void +free_dwo_file (struct dwo_file *dwo_file, struct objfile *objfile) +{ + int ix; + struct dwarf2_section_info *section; - /* Process the dies in the type unit. */ - if (die->child == NULL) - { - dump_die_for_error (die); - error (_("Dwarf Error: Missing children for type unit [in module %s]"), - bfd_get_filename (abfd)); - } + /* Note: dbfd is NULL for virtual DWO files. */ + gdb_bfd_unref (dwo_file->dbfd); - child_die = die->child; + VEC_free (dwarf2_section_info_def, dwo_file->sections.types); +} - while (child_die && child_die->tag) - { - process_die (child_die, cu); +/* Wrapper for free_dwo_file for use in cleanups. */ - child_die = sibling_die (child_die); - } +static void +free_dwo_file_cleanup (void *arg) +{ + struct dwo_file *dwo_file = (struct dwo_file *) arg; + struct objfile *objfile = dwarf2_per_objfile->objfile; - do_cleanups (back_to); + free_dwo_file (dwo_file, objfile); } -static void -add_to_cu_func_list (const char *name, CORE_ADDR lowpc, CORE_ADDR highpc, - struct dwarf2_cu *cu) +/* Traversal function for free_dwo_files. */ + +static int +free_dwo_file_from_slot (void **slot, void *info) { - struct function_range *thisfn; + struct dwo_file *dwo_file = (struct dwo_file *) *slot; + struct objfile *objfile = (struct objfile *) info; + + free_dwo_file (dwo_file, objfile); - thisfn = (struct function_range *) - obstack_alloc (&cu->comp_unit_obstack, sizeof (struct function_range)); - thisfn->name = name; - thisfn->lowpc = lowpc; - thisfn->highpc = highpc; - thisfn->seen_line = 0; - thisfn->next = NULL; + return 1; +} - if (cu->last_fn == NULL) - cu->first_fn = thisfn; - else - cu->last_fn->next = thisfn; +/* Free all resources associated with DWO_FILES. */ - cu->last_fn = thisfn; +static void +free_dwo_files (htab_t dwo_files, struct objfile *objfile) +{ + htab_traverse_noresize (dwo_files, free_dwo_file_from_slot, objfile); } + +/* Read in various DIEs. */ /* qsort helper for inherit_abstract_dies. */ @@ -5898,8 +9311,8 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu) struct die_info *child_die; unsigned die_children_count; /* CU offsets which were referenced by children of the current DIE. */ - unsigned *offsets; - unsigned *offsets_end, *offsetp; + sect_offset *offsets; + sect_offset *offsets_end, *offsetp; /* Parent of DIE - referenced by DW_AT_abstract_origin. */ struct die_info *origin_die; /* Iterator of the ORIGIN_DIE children. */ @@ -5929,7 +9342,7 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu) && origin_die->tag == DW_TAG_subprogram)) complaint (&symfile_complaints, _("DIE 0x%x and its abstract origin 0x%x have different tags"), - die->offset, origin_die->offset); + die->offset.sect_off, origin_die->offset.sect_off); child_die = die->child; die_children_count = 0; @@ -5972,13 +9385,13 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu) && child_origin_die->tag == DW_TAG_subprogram)) complaint (&symfile_complaints, _("Child DIE 0x%x and its abstract origin 0x%x have " - "different tags"), child_die->offset, - child_origin_die->offset); + "different tags"), child_die->offset.sect_off, + child_origin_die->offset.sect_off); if (child_origin_die->parent != origin_die) complaint (&symfile_complaints, _("Child DIE 0x%x and its abstract origin 0x%x have " - "different parents"), child_die->offset, - child_origin_die->offset); + "different parents"), child_die->offset.sect_off, + child_origin_die->offset.sect_off); else *offsets_end++ = child_origin_die->offset; } @@ -5987,20 +9400,22 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu) qsort (offsets, offsets_end - offsets, sizeof (*offsets), unsigned_int_compar); for (offsetp = offsets + 1; offsetp < offsets_end; offsetp++) - if (offsetp[-1] == *offsetp) + if (offsetp[-1].sect_off == offsetp->sect_off) complaint (&symfile_complaints, _("Multiple children of DIE 0x%x refer " "to DIE 0x%x as their abstract origin"), - die->offset, *offsetp); + die->offset.sect_off, offsetp->sect_off); 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) + while (offsetp < offsets_end + && offsetp->sect_off < origin_child_die->offset.sect_off) offsetp++; - if (offsetp >= offsets_end || *offsetp > origin_child_die->offset) + if (offsetp >= offsets_end + || offsetp->sect_off > origin_child_die->offset.sect_off) { /* Found that ORIGIN_CHILD_DIE is really not referenced. */ process_die (origin_child_die, origin_cu); @@ -6021,7 +9436,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) CORE_ADDR highpc; struct die_info *child_die; struct attribute *attr, *call_line, *call_file; - char *name; + const char *name; CORE_ADDR baseaddr; struct block *block; int inlined_func = (die->tag == DW_TAG_inlined_subroutine); @@ -6051,7 +9466,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) if (name == NULL) { complaint (&symfile_complaints, - _("missing name for subprogram DIE at %d"), die->offset); + _("missing name for subprogram DIE at %d"), + die->offset.sect_off); return; } @@ -6063,16 +9479,13 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("cannot get low and high bounds " "for subprogram DIE at %d"), - die->offset); + die->offset.sect_off); return; } lowpc += baseaddr; highpc += baseaddr; - /* Record the function range for dwarf_decode_lines. */ - add_to_cu_func_list (name, lowpc, highpc, cu); - /* If we have any template arguments, then we must allocate a different sort of symbol. */ for (child_die = die->child; child_die; child_die = sibling_die (child_die)) @@ -6160,10 +9573,10 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) lowpc, highpc, objfile); /* For C++, set the block's scope. */ - if (cu->language == language_cplus || cu->language == language_fortran) - cp_set_block_scope (new->name, block, &objfile->objfile_obstack, - determine_prefix (die, cu), - processing_has_namespace_info); + if ((cu->language == language_cplus || cu->language == language_fortran) + && cu->processing_has_namespace_info) + block_set_scope (block, determine_prefix (die, cu), + &objfile->objfile_obstack); /* If we have address ranges, record them. */ dwarf2_record_block_ranges (die, block, baseaddr, cu); @@ -6189,7 +9602,6 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) when we finish processing a function scope, we may need to go 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 @@ -6278,7 +9690,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("missing DW_AT_low_pc for DW_TAG_GNU_call_site " "DIE 0x%x [in module %s]"), - die->offset, cu->objfile->name); + die->offset.sect_off, objfile->name); return; } pc = DW_ADDR (attr) + baseaddr; @@ -6294,7 +9706,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("Duplicate PC %s for DW_TAG_GNU_call_site " "DIE 0x%x [in module %s]"), - paddress (gdbarch, pc), die->offset, cu->objfile->name); + paddress (gdbarch, pc), die->offset.sect_off, objfile->name); return; } @@ -6309,7 +9721,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("Tag %d is not DW_TAG_GNU_call_site_parameter in " "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"), - child_die->tag, child_die->offset, cu->objfile->name); + child_die->tag, child_die->offset.sect_off, objfile->name); continue; } @@ -6367,7 +9779,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("Cannot find function owning DW_TAG_GNU_call_site " "DIE 0x%x [in module %s]"), - die->offset, cu->objfile->name); + die->offset.sect_off, objfile->name); } } @@ -6390,7 +9802,6 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) } else if (is_ref_attr (attr)) { - struct objfile *objfile = cu->objfile; struct dwarf2_cu *target_cu = cu; struct die_info *target_die; @@ -6398,16 +9809,25 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) gdb_assert (target_cu->objfile == objfile); if (die_is_declaration (target_die, target_cu)) { - const char *target_physname; - - target_physname = dwarf2_physname (NULL, target_die, target_cu); + const char *target_physname = NULL; + struct attribute *target_attr; + + /* Prefer the mangled name; otherwise compute the demangled one. */ + target_attr = dwarf2_attr (target_die, DW_AT_linkage_name, target_cu); + if (target_attr == NULL) + target_attr = dwarf2_attr (target_die, DW_AT_MIPS_linkage_name, + target_cu); + if (target_attr != NULL && DW_STRING (target_attr) != NULL) + target_physname = DW_STRING (target_attr); + else + target_physname = dwarf2_physname (NULL, target_die, target_cu); if (target_physname == NULL) complaint (&symfile_complaints, _("DW_AT_GNU_call_site_target target DIE has invalid " "physname, for referencing DIE 0x%x [in module %s]"), - die->offset, cu->objfile->name); + die->offset.sect_off, objfile->name); else - SET_FIELD_PHYSNAME (call_site->target, (char *) target_physname); + SET_FIELD_PHYSNAME (call_site->target, target_physname); } else { @@ -6418,7 +9838,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("DW_AT_GNU_call_site_target target DIE has invalid " "low pc, for referencing DIE 0x%x [in module %s]"), - die->offset, cu->objfile->name); + die->offset.sect_off, objfile->name); else SET_FIELD_PHYSADDR (call_site->target, lowpc + baseaddr); } @@ -6427,7 +9847,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("DW_TAG_GNU_call_site DW_AT_GNU_call_site_target is neither " "block nor reference, for DIE 0x%x [in module %s]"), - die->offset, cu->objfile->name); + die->offset.sect_off, objfile->name); call_site->per_cu = cu->per_cu; @@ -6435,8 +9855,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) child_die && child_die->tag; child_die = sibling_die (child_die)) { - struct dwarf2_locexpr_baton *dlbaton; struct call_site_parameter *parameter; + struct attribute *loc, *origin; if (child_die->tag != DW_TAG_GNU_call_site_parameter) { @@ -6447,31 +9867,61 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) gdb_assert (call_site->parameter_count < nparams); parameter = &call_site->parameter[call_site->parameter_count]; - /* DW_AT_location specifies the register number. Value of the data - assumed for the register is contained in DW_AT_GNU_call_site_value. */ + /* DW_AT_location specifies the register number or DW_AT_abstract_origin + specifies DW_TAG_formal_parameter. Value of the data assumed for the + register is contained in DW_AT_GNU_call_site_value. */ - attr = dwarf2_attr (child_die, DW_AT_location, cu); - if (!attr || !attr_form_is_block (attr)) + loc = dwarf2_attr (child_die, DW_AT_location, cu); + origin = dwarf2_attr (child_die, DW_AT_abstract_origin, cu); + if (loc == NULL && origin != NULL && is_ref_attr (origin)) + { + sect_offset offset; + + parameter->kind = CALL_SITE_PARAMETER_PARAM_OFFSET; + offset = dwarf2_get_ref_die_offset (origin); + if (!offset_in_cu_p (&cu->header, offset)) + { + /* As DW_OP_GNU_parameter_ref uses CU-relative offset this + binding can be done only inside one CU. Such referenced DIE + therefore cannot be even moved to DW_TAG_partial_unit. */ + complaint (&symfile_complaints, + _("DW_AT_abstract_origin offset is not in CU for " + "DW_TAG_GNU_call_site child DIE 0x%x " + "[in module %s]"), + child_die->offset.sect_off, objfile->name); + continue; + } + parameter->u.param_offset.cu_off = (offset.sect_off + - cu->header.offset.sect_off); + } + else if (loc == NULL || origin != NULL || !attr_form_is_block (loc)) { complaint (&symfile_complaints, _("No DW_FORM_block* DW_AT_location for " "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"), - child_die->offset, cu->objfile->name); + child_die->offset.sect_off, objfile->name); continue; } - parameter->dwarf_reg = dwarf_block_to_dwarf_reg (DW_BLOCK (attr)->data, - &DW_BLOCK (attr)->data[DW_BLOCK (attr)->size]); - if (parameter->dwarf_reg == -1 - && !dwarf_block_to_sp_offset (gdbarch, DW_BLOCK (attr)->data, - &DW_BLOCK (attr)->data[DW_BLOCK (attr)->size], - ¶meter->fb_offset)) + else { - complaint (&symfile_complaints, - _("Only single DW_OP_reg or DW_OP_fbreg is supported " - "for DW_FORM_block* DW_AT_location for " - "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"), - child_die->offset, cu->objfile->name); - continue; + parameter->u.dwarf_reg = dwarf_block_to_dwarf_reg + (DW_BLOCK (loc)->data, &DW_BLOCK (loc)->data[DW_BLOCK (loc)->size]); + if (parameter->u.dwarf_reg != -1) + parameter->kind = CALL_SITE_PARAMETER_DWARF_REG; + else if (dwarf_block_to_sp_offset (gdbarch, DW_BLOCK (loc)->data, + &DW_BLOCK (loc)->data[DW_BLOCK (loc)->size], + ¶meter->u.fb_offset)) + parameter->kind = CALL_SITE_PARAMETER_FB_OFFSET; + else + { + complaint (&symfile_complaints, + _("Only single DW_OP_reg or DW_OP_fbreg is supported " + "for DW_FORM_block* DW_AT_location is supported for " + "DW_TAG_GNU_call_site child DIE 0x%x " + "[in module %s]"), + child_die->offset.sect_off, objfile->name); + continue; + } } attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_value, cu); @@ -6480,7 +9930,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("No DW_FORM_block* DW_AT_GNU_call_site_value for " "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"), - child_die->offset, cu->objfile->name); + child_die->offset.sect_off, objfile->name); continue; } parameter->value = DW_BLOCK (attr)->data; @@ -6498,7 +9948,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("No DW_FORM_block* DW_AT_GNU_call_site_data_value for " "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"), - child_die->offset, cu->objfile->name); + child_die->offset.sect_off, objfile->name); else { parameter->data_value = DW_BLOCK (attr)->data; @@ -6613,6 +10063,17 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return, range_beginning += base; range_end += base; + /* A not-uncommon case of bad debug info. + Don't pollute the addrmap with bad data. */ + if (range_beginning + baseaddr == 0 + && !dwarf2_per_objfile->has_section_at_zero) + { + complaint (&symfile_complaints, + _(".debug_ranges entry has start address of zero" + " [in module %s]"), objfile->name); + continue; + } + if (ranges_pst != NULL) addrmap_set_empty (objfile->psymtabs_addrmap, range_beginning + baseaddr, @@ -6653,23 +10114,31 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return, /* Get low and high pc attributes from a die. Return 1 if the attributes are present and valid, otherwise, return 0. Return -1 if the range is 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, struct partial_symtab *pst) { struct attribute *attr; + struct attribute *attr_high; CORE_ADDR low = 0; CORE_ADDR high = 0; int ret = 0; - attr = dwarf2_attr (die, DW_AT_high_pc, cu); - if (attr) + attr_high = dwarf2_attr (die, DW_AT_high_pc, cu); + if (attr_high) { - high = DW_ADDR (attr); attr = dwarf2_attr (die, DW_AT_low_pc, cu); if (attr) - low = DW_ADDR (attr); + { + low = DW_ADDR (attr); + if (attr_high->form == DW_FORM_addr + || attr_high->form == DW_FORM_GNU_addr_index) + high = DW_ADDR (attr_high); + else + high = low + DW_UNSND (attr_high); + } else /* Found high w/o low attribute. */ return 0; @@ -6682,9 +10151,18 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, attr = dwarf2_attr (die, DW_AT_ranges, cu); if (attr != NULL) { + /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton. + We take advantage of the fact that DW_AT_ranges does not appear + in DW_TAG_compile_unit of DWO files. */ + int need_ranges_base = die->tag != DW_TAG_compile_unit; + unsigned int ranges_offset = (DW_UNSND (attr) + + (need_ranges_base + ? cu->ranges_base + : 0)); + /* 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, pst)) + if (!dwarf2_ranges_read (ranges_offset, &low, &high, cu, pst)) return 0; /* Found discontinuous range of addresses. */ ret = -1; @@ -6810,21 +10288,28 @@ get_scope_pc_bounds (struct die_info *die, /* Record the address ranges for BLOCK, offset by BASEADDR, as given in DIE. */ + static void dwarf2_record_block_ranges (struct die_info *die, struct block *block, CORE_ADDR baseaddr, struct dwarf2_cu *cu) { + struct objfile *objfile = cu->objfile; struct attribute *attr; + struct attribute *attr_high; - attr = dwarf2_attr (die, DW_AT_high_pc, cu); - if (attr) + attr_high = dwarf2_attr (die, DW_AT_high_pc, cu); + if (attr_high) { - CORE_ADDR high = DW_ADDR (attr); - attr = dwarf2_attr (die, DW_AT_low_pc, cu); if (attr) { CORE_ADDR low = DW_ADDR (attr); + CORE_ADDR high; + if (attr_high->form == DW_FORM_addr + || attr_high->form == DW_FORM_GNU_addr_index) + high = DW_ADDR (attr_high); + else + high = low + DW_UNSND (attr_high); record_block_range (block, baseaddr + low, baseaddr + high - 1); } @@ -6833,11 +10318,16 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block, attr = dwarf2_attr (die, DW_AT_ranges, cu); if (attr) { - bfd *obfd = cu->objfile->obfd; + bfd *obfd = objfile->obfd; + /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton. + We take advantage of the fact that DW_AT_ranges does not appear + in DW_TAG_compile_unit of DWO files. */ + int need_ranges_base = die->tag != DW_TAG_compile_unit; /* The value of the DW_AT_ranges attribute is the offset of the address range list in the .debug_ranges section. */ - unsigned long offset = DW_UNSND (attr); + unsigned long offset = (DW_UNSND (attr) + + (need_ranges_base ? cu->ranges_base : 0)); gdb_byte *buffer = dwarf2_per_objfile->ranges.buffer + offset; /* For some target architectures, but not others, the @@ -6911,20 +10401,30 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block, if (start == end) continue; - record_block_range (block, - baseaddr + base + start, - baseaddr + base + end - 1); + start += base + baseaddr; + end += base + baseaddr; + + /* A not-uncommon case of bad debug info. + Don't pollute the addrmap with bad data. */ + if (start == 0 && !dwarf2_per_objfile->has_section_at_zero) + { + complaint (&symfile_complaints, + _(".debug_ranges entry has start address of zero" + " [in module %s]"), objfile->name); + continue; + } + + record_block_range (block, start, end - 1); } } } } -/* Check for GCC PR debug/45124 fix which is not present in any G++ version up - to 4.5.any while it is present already in G++ 4.6.0 - the PR has been fixed - during 4.6.0 experimental. */ +/* Check whether the producer field indicates either of GCC < 4.6, or the + Intel C/C++ compiler, and cache the result in CU. */ -static int -producer_is_gxx_lt_4_6 (struct dwarf2_cu *cu) +static void +check_producer (struct dwarf2_cu *cu) { const char *cs; int major, minor, release; @@ -6939,30 +10439,46 @@ producer_is_gxx_lt_4_6 (struct dwarf2_cu *cu) for their space efficiency GDB cannot workaround gcc-4.5.x -gdwarf-4 combination. gcc-4.5.x -gdwarf-4 binaries have DW_AT_accessibility interpreted incorrectly by GDB now - GCC PR debug/48229. */ - - return 0; } - - /* Skip any identifier after "GNU " - such as "C++" or "Java". */ - - if (strncmp (cu->producer, "GNU ", strlen ("GNU ")) != 0) + else if (strncmp (cu->producer, "GNU ", strlen ("GNU ")) == 0) { - /* For non-GCC compilers expect their behavior is DWARF version - compliant. */ + /* Skip any identifier after "GNU " - such as "C++" or "Java". */ - return 0; + cs = &cu->producer[strlen ("GNU ")]; + while (*cs && !isdigit (*cs)) + cs++; + if (sscanf (cs, "%d.%d.%d", &major, &minor, &release) != 3) + { + /* Not recognized as GCC. */ + } + else + { + cu->producer_is_gxx_lt_4_6 = major < 4 || (major == 4 && minor < 6); + cu->producer_is_gcc_lt_4_3 = major < 4 || (major == 4 && minor < 3); + } } - cs = &cu->producer[strlen ("GNU ")]; - while (*cs && !isdigit (*cs)) - cs++; - if (sscanf (cs, "%d.%d.%d", &major, &minor, &release) != 3) + else if (strncmp (cu->producer, "Intel(R) C", strlen ("Intel(R) C")) == 0) + cu->producer_is_icc = 1; + else { - /* Not recognized as GCC. */ - - return 0; + /* For other non-GCC compilers, expect their behavior is DWARF version + compliant. */ } - return major < 4 || (major == 4 && minor < 6); + cu->checked_producer = 1; +} + +/* Check for GCC PR debug/45124 fix which is not present in any G++ version up + to 4.5.any while it is present already in G++ 4.6.0 - the PR has been fixed + during 4.6.0 experimental. */ + +static int +producer_is_gxx_lt_4_6 (struct dwarf2_cu *cu) +{ + if (!cu->checked_producer) + check_producer (cu); + + return cu->producer_is_gxx_lt_4_6; } /* Return the default accessibility type if it is not overriden by @@ -7040,7 +10556,7 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, struct nextfield *new_field; struct attribute *attr; struct field *fp; - char *fieldname = ""; + const char *fieldname = ""; /* Allocate a new field list entry and link it in. */ new_field = (struct nextfield *) xmalloc (sizeof (struct nextfield)); @@ -7110,7 +10626,7 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, anonymous object to the MSB of the field. We don't have to do anything special since we don't need to know the size of the anonymous object. */ - FIELD_BITPOS (*fp) += DW_UNSND (attr); + SET_FIELD_BITPOS (*fp, FIELD_BITPOS (*fp) + DW_UNSND (attr)); } else { @@ -7139,8 +10655,10 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, bit field. */ anonymous_size = TYPE_LENGTH (fp->type); } - FIELD_BITPOS (*fp) += anonymous_size * bits_per_byte - - bit_offset - FIELD_BITSIZE (*fp); + SET_FIELD_BITPOS (*fp, + (FIELD_BITPOS (*fp) + + anonymous_size * bits_per_byte + - bit_offset - FIELD_BITSIZE (*fp))); } } @@ -7349,6 +10867,34 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type, } } +/* Return true if this member function is a constructor, false + otherwise. */ + +static int +dwarf2_is_constructor (struct die_info *die, struct dwarf2_cu *cu) +{ + const char *fieldname; + const char *typename; + int len; + + if (die->parent == NULL) + return 0; + + if (die->parent->tag != DW_TAG_structure_type + && die->parent->tag != DW_TAG_union_type + && die->parent->tag != DW_TAG_class_type) + return 0; + + fieldname = dwarf2_name (die, cu); + typename = dwarf2_name (die->parent, cu); + if (fieldname == NULL || typename == NULL) + return 0; + + len = strlen (fieldname); + return (strncmp (fieldname, typename, len) == 0 + && (typename[len] == '\0' || typename[len] == '<')); +} + /* Add a member function to the proper fieldlist. */ static void @@ -7360,7 +10906,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, struct fnfieldlist *flp; int i; struct fn_field *fnp; - char *fieldname; + const char *fieldname; struct nextfnfield *new_fnfield; struct type *this_type; enum dwarf_access_attribute accessibility; @@ -7480,6 +11026,8 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, if (attr && DW_UNSND (attr) != 0) fnp->is_artificial = 1; + fnp->is_constructor = dwarf2_is_constructor (die, cu); + /* Get index in virtual function table if it is a virtual member function. For older versions of GCC, this is an offset in the appropriate virtual table, as specified by DW_AT_containing_type. @@ -7540,7 +11088,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, complaint (&symfile_complaints, _("Member function \"%s\" (offset %d) is virtual " "but the vtable offset is not specified"), - fieldname, die->offset); + fieldname, die->offset.sect_off); ALLOCATE_CPLUS_STRUCT_TYPE (type); TYPE_CPLUS_DYNAMIC (type) = 1; } @@ -7554,7 +11102,6 @@ dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type, struct dwarf2_cu *cu) { struct fnfieldlist *flp; - int total_length = 0; int i; if (cu->language == language_ada) @@ -7576,12 +11123,9 @@ dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type, TYPE_ALLOC (type, sizeof (struct fn_field) * flp->length); for (k = flp->length; (k--, nfp); nfp = nfp->next) fn_flp->fn_fields[k] = nfp->fnfield; - - total_length += flp->length; } TYPE_NFN_FIELDS (type) = fip->nfnfields; - TYPE_NFN_FIELDS_TOTAL (type) = total_length; } /* Returns non-zero if NAME is the name of a vtable member in CU's @@ -7647,6 +11191,18 @@ quirk_gcc_member_function_pointer (struct type *type, struct objfile *objfile) smash_to_methodptr_type (type, new_type); } +/* Return non-zero if the CU's PRODUCER string matches the Intel C/C++ compiler + (icc). */ + +static int +producer_is_icc (struct dwarf2_cu *cu) +{ + if (!cu->checked_producer) + check_producer (cu); + + return cu->producer_is_icc; +} + /* Called when we find the DIE that starts a structure or union scope (definition) to create a type for the structure or union. Fill in the type's name and general properties; the members will not be @@ -7670,12 +11226,12 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) struct objfile *objfile = cu->objfile; struct type *type; struct attribute *attr; - char *name; + const char *name; /* If the definition of this type lives in .debug_types, read that type. Don't follow DW_AT_specification though, that will take us back up the chain and we want to go down. */ - attr = dwarf2_attr_no_follow (die, DW_AT_signature, cu); + attr = dwarf2_attr_no_follow (die, DW_AT_signature); if (attr) { struct dwarf2_cu *type_cu = cu; @@ -7701,7 +11257,7 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) if (cu->language == language_cplus || cu->language == language_java) { - char *full_name = (char *) dwarf2_full_name (name, die, cu); + const char *full_name = dwarf2_full_name (name, die, cu); /* dwarf2_full_name might have already finished building the DIE's type. If so, there is no need to continue. */ @@ -7717,7 +11273,7 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) { /* The name is already allocated along with this objfile, so we don't need to duplicate it for the type. */ - TYPE_TAG_NAME (type) = (char *) name; + TYPE_TAG_NAME (type) = name; if (die->tag == DW_TAG_class_type) TYPE_NAME (type) = TYPE_TAG_NAME (type); } @@ -7749,7 +11305,14 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) TYPE_LENGTH (type) = 0; } - TYPE_STUB_SUPPORTED (type) = 1; + if (producer_is_icc (cu)) + { + /* ICC does not output the required DW_AT_declaration + on incomplete types, but gives them a size of zero. */ + } + else + TYPE_STUB_SUPPORTED (type) = 1; + if (die_is_declaration (die, cu)) TYPE_STUB (type) = 1; else if (attr == NULL && die->child == NULL @@ -7873,7 +11436,7 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu) i >= TYPE_N_BASECLASSES (t); --i) { - char *fieldname = TYPE_FIELD_NAME (t, i); + const char *fieldname = TYPE_FIELD_NAME (t, i); if (is_vtable_name (fieldname, cu)) { @@ -7948,7 +11511,7 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu) TYPE_CPLUS_REALLY_JAVA (type) = cu->language == language_java; } - quirk_gcc_member_function_pointer (type, cu->objfile); + quirk_gcc_member_function_pointer (type, objfile); /* NOTE: carlton/2004-03-16: GCC 3.4 (or at least one of its snapshots) has been known to create a die giving a declaration @@ -7995,7 +11558,7 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) /* If the definition of this type lives in .debug_types, read that type. Don't follow DW_AT_specification though, that will take us back up the chain and we want to go down. */ - attr = dwarf2_attr_no_follow (die, DW_AT_signature, cu); + attr = dwarf2_attr_no_follow (die, DW_AT_signature); if (attr) { struct dwarf2_cu *type_cu = cu; @@ -8013,7 +11576,7 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) TYPE_CODE (type) = TYPE_CODE_ENUM; name = dwarf2_full_name (NULL, die, cu); if (name != NULL) - TYPE_TAG_NAME (type) = (char *) name; + TYPE_TAG_NAME (type) = name; attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr) @@ -8058,7 +11621,9 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) struct field *fields = NULL; int num_fields = 0; int unsigned_enum = 1; - char *name; + const char *name; + int flag_enum = 1; + ULONGEST mask = 0; child_die = die->child; while (child_die && child_die->tag) @@ -8074,7 +11639,14 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) { sym = new_symbol (child_die, this_type, cu); if (SYMBOL_VALUE (sym) < 0) - unsigned_enum = 0; + { + unsigned_enum = 0; + flag_enum = 0; + } + else if ((mask & SYMBOL_VALUE (sym)) != 0) + flag_enum = 0; + else + mask |= SYMBOL_VALUE (sym); if ((num_fields % DW_FIELD_ALLOC_CHUNK) == 0) { @@ -8086,7 +11658,7 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) FIELD_NAME (fields[num_fields]) = SYMBOL_LINKAGE_NAME (sym); FIELD_TYPE (fields[num_fields]) = NULL; - SET_FIELD_BITPOS (fields[num_fields], SYMBOL_VALUE (sym)); + SET_FIELD_ENUMVAL (fields[num_fields], SYMBOL_VALUE (sym)); FIELD_BITSIZE (fields[num_fields]) = 0; num_fields++; @@ -8107,6 +11679,8 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) } if (unsigned_enum) TYPE_UNSIGNED (this_type) = 1; + if (flag_enum) + TYPE_FLAG_ENUM (this_type) = 1; } /* If we are reading an enum from a .debug_types unit, and the enum @@ -8117,16 +11691,17 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) actually available. Note that we do not want to do this for all enums which are just declarations, because C++0x allows forward enum declarations. */ - if (cu->per_cu->debug_types_section + if (cu->per_cu->is_debug_types && die_is_declaration (die, cu)) { - struct signatured_type *type_sig; + struct signatured_type *sig_type; - type_sig + sig_type = lookup_signatured_type_at_offset (dwarf2_per_objfile->objfile, - cu->per_cu->debug_types_section, + cu->per_cu->info_or_types_section, cu->per_cu->offset); - if (type_sig->type_offset != die->offset) + gdb_assert (sig_type->type_offset_in_section.sect_off != 0); + if (sig_type->type_offset_in_section.sect_off != die->offset.sect_off) return; } @@ -8148,7 +11723,7 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu) struct attribute *attr; int ndim = 0; struct cleanup *back_to; - char *name; + const char *name; element_type = die_type (die, cu); @@ -8307,15 +11882,89 @@ 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. */ +/* A helper for read_common_block that creates a locexpr baton. + SYM is the symbol which we are marking as computed. + COMMON_DIE is the DIE for the common block. + COMMON_LOC is the location expression attribute for the common + block itself. + MEMBER_LOC is the location expression attribute for the particular + member of the common block that we are processing. + CU is the CU from which the above come. */ + +static void +mark_common_block_symbol_computed (struct symbol *sym, + struct die_info *common_die, + struct attribute *common_loc, + struct attribute *member_loc, + struct dwarf2_cu *cu) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_locexpr_baton *baton; + gdb_byte *ptr; + unsigned int cu_off; + enum bfd_endian byte_order = gdbarch_byte_order (get_objfile_arch (objfile)); + LONGEST offset = 0; + + gdb_assert (common_loc && member_loc); + gdb_assert (attr_form_is_block (common_loc)); + gdb_assert (attr_form_is_block (member_loc) + || attr_form_is_constant (member_loc)); + + baton = obstack_alloc (&objfile->objfile_obstack, + sizeof (struct dwarf2_locexpr_baton)); + baton->per_cu = cu->per_cu; + gdb_assert (baton->per_cu); + + baton->size = 5 /* DW_OP_call4 */ + 1 /* DW_OP_plus */; + + if (attr_form_is_constant (member_loc)) + { + offset = dwarf2_get_attr_constant_value (member_loc, 0); + baton->size += 1 /* DW_OP_addr */ + cu->header.addr_size; + } + else + baton->size += DW_BLOCK (member_loc)->size; + + ptr = obstack_alloc (&objfile->objfile_obstack, baton->size); + baton->data = ptr; + + *ptr++ = DW_OP_call4; + cu_off = common_die->offset.sect_off - cu->per_cu->offset.sect_off; + store_unsigned_integer (ptr, 4, byte_order, cu_off); + ptr += 4; + + if (attr_form_is_constant (member_loc)) + { + *ptr++ = DW_OP_addr; + store_unsigned_integer (ptr, cu->header.addr_size, byte_order, offset); + ptr += cu->header.addr_size; + } + else + { + /* We have to copy the data here, because DW_OP_call4 will only + use a DW_AT_location attribute. */ + memcpy (ptr, DW_BLOCK (member_loc)->data, DW_BLOCK (member_loc)->size); + ptr += DW_BLOCK (member_loc)->size; + } + + *ptr++ = DW_OP_plus; + gdb_assert (ptr - baton->data == baton->size); + + SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs; + SYMBOL_LOCATION_BATON (sym) = baton; + SYMBOL_CLASS (sym) = LOC_COMPUTED; +} + +/* Create appropriate locally-scoped variables for all the + DW_TAG_common_block entries. Also create a struct common_block + listing all such variables 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; attr = dwarf2_attr (die, DW_AT_location, cu); if (attr) @@ -8323,34 +11972,84 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu) /* Support the .debug_loc offsets. */ if (attr_form_is_block (attr)) { - base = decode_locdesc (DW_BLOCK (attr), cu); + /* Ok. */ } else if (attr_form_is_section_offset (attr)) { dwarf2_complex_location_expr_complaint (); + attr = NULL; } else { dwarf2_invalid_attrib_class_complaint ("DW_AT_location", "common block member"); + attr = NULL; } } + if (die->child != NULL) { - child_die = die->child; - while (child_die && child_die->tag) - { - LONGEST offset; + struct objfile *objfile = cu->objfile; + struct die_info *child_die; + size_t n_entries = 0, size; + struct common_block *common_block; + struct symbol *sym; + + for (child_die = die->child; + child_die && child_die->tag; + child_die = sibling_die (child_die)) + ++n_entries; + size = (sizeof (struct common_block) + + (n_entries - 1) * sizeof (struct symbol *)); + common_block = obstack_alloc (&objfile->objfile_obstack, size); + memset (common_block->contents, 0, n_entries * sizeof (struct symbol *)); + common_block->n_entries = 0; + + for (child_die = die->child; + child_die && child_die->tag; + child_die = sibling_die (child_die)) + { + /* Create the symbol in the DW_TAG_common_block block in the current + symbol scope. */ sym = new_symbol (child_die, NULL, cu); - if (sym != NULL - && handle_data_member_location (child_die, cu, &offset)) + if (sym != NULL) { - SYMBOL_VALUE_ADDRESS (sym) = base + offset; - add_symbol_to_list (sym, &global_symbols); + struct attribute *member_loc; + + common_block->contents[common_block->n_entries++] = sym; + + member_loc = dwarf2_attr (child_die, DW_AT_data_member_location, + cu); + if (member_loc) + { + /* GDB has handled this for a long time, but it is + not specified by DWARF. It seems to have been + emitted by gfortran at least as recently as: + http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23057. */ + complaint (&symfile_complaints, + _("Variable in common block has " + "DW_AT_data_member_location " + "- DIE at 0x%x [in module %s]"), + child_die->offset.sect_off, cu->objfile->name); + + if (attr_form_is_section_offset (member_loc)) + dwarf2_complex_location_expr_complaint (); + else if (attr_form_is_constant (member_loc) + || attr_form_is_block (member_loc)) + { + if (attr) + mark_common_block_symbol_computed (sym, die, attr, + member_loc, cu); + } + else + dwarf2_complex_location_expr_complaint (); + } } - child_die = sibling_die (child_die); } + + sym = new_symbol (die, objfile_type (objfile)->builtin_void, cu); + SYMBOL_VALUE_COMMON_BLOCK (sym) = common_block; } } @@ -8390,7 +12089,7 @@ read_namespace_type (struct die_info *die, struct dwarf2_cu *cu) /* Create the type. */ type = init_type (TYPE_CODE_NAMESPACE, 0, 0, NULL, objfile); - TYPE_NAME (type) = (char *) name; + TYPE_NAME (type) = name; TYPE_TAG_NAME (type) = TYPE_NAME (type); return set_die_type (die, type, cu); @@ -8421,7 +12120,7 @@ read_namespace (struct die_info *die, struct dwarf2_cu *cu) const char *previous_prefix = determine_prefix (die, cu); cp_add_using_directive (previous_prefix, TYPE_NAME (type), NULL, - NULL, NULL, &objfile->objfile_obstack); + NULL, NULL, 0, &objfile->objfile_obstack); } } @@ -8445,14 +12144,14 @@ static struct type * read_module_type (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; - char *module_name; + const char *module_name; struct type *type; module_name = dwarf2_name (die, cu); if (!module_name) complaint (&symfile_complaints, _("DW_TAG_module has no name, offset 0x%x"), - die->offset); + die->offset.sect_off); type = init_type (TYPE_CODE_MODULE, 0, 0, module_name, objfile); /* determine_prefix uses TYPE_TAG_NAME. */ @@ -8590,6 +12289,15 @@ read_tag_ptr_to_member_type (struct die_info *die, struct dwarf2_cu *cu) if (TYPE_CODE (check_typedef (to_type)) == TYPE_CODE_METHOD) type = lookup_methodptr_type (to_type); + else if (TYPE_CODE (check_typedef (to_type)) == TYPE_CODE_FUNC) + { + struct type *new_type = alloc_type (cu->objfile); + + smash_to_method_type (new_type, domain, TYPE_TARGET_TYPE (to_type), + TYPE_FIELDS (to_type), TYPE_NFIELDS (to_type), + TYPE_VARARGS (to_type)); + type = lookup_methodptr_type (new_type); + } else type = lookup_memberptr_type (to_type, domain); @@ -8681,6 +12389,24 @@ read_tag_volatile_type (struct die_info *die, struct dwarf2_cu *cu) return set_die_type (die, cv_type, cu); } +/* Handle DW_TAG_restrict_type. */ + +static struct type * +read_tag_restrict_type (struct die_info *die, struct dwarf2_cu *cu) +{ + struct type *base_type, *cv_type; + + base_type = die_type (die, cu); + + /* The die_type call above may have already set the type for this DIE. */ + cv_type = get_die_type (die, cu); + if (cv_type) + return cv_type; + + cv_type = make_restrict_type (base_type); + return set_die_type (die, cv_type, cu); +} + /* Extract all information from a DW_TAG_string_type DIE and add to the user defined type vector. It isn't really a user defined type, but it behaves like one, with other DIE's using an AT_user_def_type @@ -8735,6 +12461,7 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu) static struct type * read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu) { + struct objfile *objfile = cu->objfile; struct type *type; /* Type that this function returns. */ struct type *ftype; /* Function that returns above type. */ struct attribute *attr; @@ -8780,7 +12507,7 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu) if (die->child != NULL) { - struct type *void_type = objfile_type (cu->objfile)->builtin_void; + struct type *void_type = objfile_type (objfile)->builtin_void; struct die_info *child_die; int nparams, iparams; @@ -8890,14 +12617,26 @@ read_typedef (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; const char *name = NULL; - struct type *this_type; + struct type *this_type, *target_type; name = dwarf2_full_name (NULL, die, cu); this_type = init_type (TYPE_CODE_TYPEDEF, 0, TYPE_FLAG_TARGET_STUB, NULL, objfile); - TYPE_NAME (this_type) = (char *) name; + TYPE_NAME (this_type) = name; set_die_type (die, this_type, cu); - TYPE_TARGET_TYPE (this_type) = die_type (die, cu); + target_type = die_type (die, cu); + if (target_type != this_type) + TYPE_TARGET_TYPE (this_type) = target_type; + else + { + /* Self-referential typedefs are, it seems, not allowed by the DWARF + spec and cause infinite loops in GDB. */ + complaint (&symfile_complaints, + _("Self-referential DW_TAG_typedef " + "- DIE at 0x%x [in module %s]"), + die->offset.sect_off, objfile->name); + TYPE_TARGET_TYPE (this_type) = NULL; + } return this_type; } @@ -8911,7 +12650,7 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) struct type *type; struct attribute *attr; int encoding = 0, size = 0; - char *name; + const char *name; enum type_code code = TYPE_CODE_INT; int type_flags = 0; struct type *target_type = NULL; @@ -9003,27 +12742,55 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) static struct type * read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) { - struct type *base_type; + struct type *base_type, *orig_base_type; struct type *range_type; struct attribute *attr; - LONGEST low = 0; - LONGEST high = -1; - char *name; + LONGEST low, high; + int low_default_is_valid; + const char *name; LONGEST negative_mask; - base_type = die_type (die, cu); - /* Preserve BASE_TYPE's original type, just set its LENGTH. */ - check_typedef (base_type); + orig_base_type = die_type (die, cu); + /* If ORIG_BASE_TYPE is a typedef, it will not be TYPE_UNSIGNED, + whereas the real type might be. So, we use ORIG_BASE_TYPE when + creating the range type, but we use the result of check_typedef + when examining properties of the type. */ + base_type = check_typedef (orig_base_type); /* The die_type call above may have already set the type for this DIE. */ range_type = get_die_type (die, cu); if (range_type) return range_type; - if (cu->language == language_fortran) + /* Set LOW_DEFAULT_IS_VALID if current language and DWARF version allow + omitting DW_AT_lower_bound. */ + switch (cu->language) { - /* FORTRAN implies a lower bound of 1, if not given. */ + case language_c: + case language_cplus: + low = 0; + low_default_is_valid = 1; + break; + case language_fortran: + low = 1; + low_default_is_valid = 1; + break; + case language_d: + case language_java: + case language_objc: + low = 0; + low_default_is_valid = (cu->header.version >= 4); + break; + case language_ada: + case language_m2: + case language_pascal: low = 1; + low_default_is_valid = (cu->header.version >= 4); + break; + default: + low = 0; + low_default_is_valid = 0; + break; } /* FIXME: For variable sized arrays either of these could be @@ -9031,7 +12798,11 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) 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); + low = dwarf2_get_attr_constant_value (attr, low); + else if (!low_default_is_valid) + complaint (&symfile_complaints, _("Missing DW_AT_lower_bound " + "- DIE at 0x%x [in module %s]"), + die->offset.sect_off, cu->objfile->name); attr = dwarf2_attr (die, DW_AT_upper_bound, cu); if (attr) @@ -9114,131 +12885,45 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) if (!TYPE_UNSIGNED (base_type) && (high & negative_mask)) high |= negative_mask; - range_type = create_range_type (NULL, base_type, low, high); + range_type = create_range_type (NULL, orig_base_type, low, high); /* Mark arrays with dynamic length at least as an array of unspecified length. GDB could check the boundary but before it gets implemented at least allow accessing the array elements. */ if (attr && attr_form_is_block (attr)) - TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; - - /* Ada expects an empty array on no boundary attributes. */ - if (attr == NULL && cu->language != language_ada) - TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; - - name = dwarf2_name (die, cu); - if (name) - TYPE_NAME (range_type) = name; - - attr = dwarf2_attr (die, DW_AT_byte_size, cu); - if (attr) - TYPE_LENGTH (range_type) = DW_UNSND (attr); - - set_die_type (die, range_type, cu); - - /* set_die_type should be already done. */ - set_descriptive_type (range_type, die, cu); - - return range_type; -} - -static struct type * -read_unspecified_type (struct die_info *die, struct dwarf2_cu *cu) -{ - struct type *type; - - /* For now, we only support the C meaning of an unspecified type: void. */ - - type = init_type (TYPE_CODE_VOID, 0, 0, NULL, cu->objfile); - TYPE_NAME (type) = dwarf2_name (die, cu); - - return set_die_type (die, type, cu); -} - -/* Trivial hash function for die_info: the hash value of a DIE - is its offset in .debug_info for this objfile. */ - -static hashval_t -die_hash (const void *item) -{ - const struct die_info *die = item; - - return die->offset; -} - -/* Trivial comparison function for die_info structures: two DIEs - are equal if they have the same offset. */ - -static int -die_eq (const void *item_lhs, const void *item_rhs) -{ - const struct die_info *die_lhs = item_lhs; - const struct die_info *die_rhs = item_rhs; - - return die_lhs->offset == die_rhs->offset; -} - -/* Read a whole compilation unit into a linked list of dies. */ - -static struct die_info * -read_comp_unit (gdb_byte *info_ptr, struct dwarf2_cu *cu) -{ - struct die_reader_specs reader_specs; - int read_abbrevs = 0; - struct cleanup *back_to = NULL; - struct die_info *die; + TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; - if (cu->dwarf2_abbrevs == NULL) - { - dwarf2_read_abbrevs (cu->objfile->obfd, cu); - back_to = make_cleanup (dwarf2_free_abbrev_table, cu); - read_abbrevs = 1; - } + /* Ada expects an empty array on no boundary attributes. */ + if (attr == NULL && cu->language != language_ada) + TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; - gdb_assert (cu->die_hash == NULL); - cu->die_hash - = htab_create_alloc_ex (cu->header.length / 12, - die_hash, - die_eq, - NULL, - &cu->comp_unit_obstack, - hashtab_obstack_allocate, - dummy_obstack_deallocate); + name = dwarf2_name (die, cu); + if (name) + TYPE_NAME (range_type) = name; - init_cu_die_reader (&reader_specs, cu); + attr = dwarf2_attr (die, DW_AT_byte_size, cu); + if (attr) + TYPE_LENGTH (range_type) = DW_UNSND (attr); - die = read_die_and_children (&reader_specs, info_ptr, &info_ptr, NULL); + set_die_type (die, range_type, cu); - if (read_abbrevs) - do_cleanups (back_to); + /* set_die_type should be already done. */ + set_descriptive_type (range_type, die, cu); - return die; + return range_type; } -/* Main entry point for reading a DIE and all children. - Read the DIE and dump it if requested. */ - -static struct die_info * -read_die_and_children (const struct die_reader_specs *reader, - gdb_byte *info_ptr, - gdb_byte **new_info_ptr, - struct die_info *parent) +static struct type * +read_unspecified_type (struct die_info *die, struct dwarf2_cu *cu) { - struct die_info *result = read_die_and_children_1 (reader, info_ptr, - new_info_ptr, parent); + struct type *type; - if (dwarf2_die_debug) - { - fprintf_unfiltered (gdb_stdlog, - "\nRead die from %s of %s:\n", - (reader->cu->per_cu->debug_types_section - ? ".debug_types" - : ".debug_info"), - reader->abfd->filename); - dump_die (result, dwarf2_die_debug); - } + /* For now, we only support the C meaning of an unspecified type: void. */ - return result; + type = init_type (TYPE_CODE_VOID, 0, 0, NULL, cu->objfile); + TYPE_NAME (type) = dwarf2_name (die, cu); + + return set_die_type (die, type, cu); } /* Read a single die and all its descendents. Set the die's sibling @@ -9248,10 +12933,10 @@ read_die_and_children (const struct die_reader_specs *reader, is the parent of the die in question. */ static struct die_info * -read_die_and_children_1 (const struct die_reader_specs *reader, - gdb_byte *info_ptr, - gdb_byte **new_info_ptr, - struct die_info *parent) +read_die_and_children (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + gdb_byte **new_info_ptr, + struct die_info *parent) { struct die_info *die; gdb_byte *cur_ptr; @@ -9297,7 +12982,7 @@ read_die_and_siblings (const struct die_reader_specs *reader, while (1) { struct die_info *die - = read_die_and_children_1 (reader, cur_ptr, &cur_ptr, parent); + = read_die_and_children (reader, cur_ptr, &cur_ptr, parent); if (die == NULL) { @@ -9314,23 +12999,27 @@ read_die_and_siblings (const struct die_reader_specs *reader, } } -/* Read the die from the .debug_info section buffer. Set DIEP to - point to a newly allocated die with its information, except for its - child, sibling, and parent fields. Set HAS_CHILDREN to tell - whether the die has children or not. */ +/* Read a die and all its attributes, leave space for NUM_EXTRA_ATTRS + attributes. + The caller is responsible for filling in the extra attributes + and updating (*DIEP)->num_attrs. + Set DIEP to point to a newly allocated die with its information, + except for its child, sibling, and parent fields. + Set HAS_CHILDREN to tell whether the die has children or not. */ static gdb_byte * -read_full_die (const struct die_reader_specs *reader, - struct die_info **diep, gdb_byte *info_ptr, - int *has_children) +read_full_die_1 (const struct die_reader_specs *reader, + struct die_info **diep, gdb_byte *info_ptr, + int *has_children, int num_extra_attrs) { - unsigned int abbrev_number, bytes_read, i, offset; + unsigned int abbrev_number, bytes_read, i; + sect_offset offset; struct abbrev_info *abbrev; struct die_info *die; struct dwarf2_cu *cu = reader->cu; bfd *abfd = reader->abfd; - offset = info_ptr - reader->buffer; + offset.sect_off = info_ptr - reader->buffer; abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; if (!abbrev_number) @@ -9340,56 +13029,127 @@ read_full_die (const struct die_reader_specs *reader, return info_ptr; } - abbrev = dwarf2_lookup_abbrev (abbrev_number, cu); + abbrev = abbrev_table_lookup_abbrev (cu->abbrev_table, abbrev_number); if (!abbrev) error (_("Dwarf Error: could not find abbrev number %d [in module %s]"), abbrev_number, bfd_get_filename (abfd)); - die = dwarf_alloc_die (cu, abbrev->num_attrs); + die = dwarf_alloc_die (cu, abbrev->num_attrs + num_extra_attrs); die->offset = offset; die->tag = abbrev->tag; die->abbrev = abbrev_number; + /* Make the result usable. + The caller needs to update num_attrs after adding the extra + attributes. */ die->num_attrs = abbrev->num_attrs; for (i = 0; i < abbrev->num_attrs; ++i) - info_ptr = read_attribute (&die->attrs[i], &abbrev->attrs[i], - abfd, info_ptr, cu); + info_ptr = read_attribute (reader, &die->attrs[i], &abbrev->attrs[i], + info_ptr); *diep = die; *has_children = abbrev->has_children; return info_ptr; } -/* In DWARF version 2, the description of the debugging information is +/* Read a die and all its attributes. + Set DIEP to point to a newly allocated die with its information, + except for its child, sibling, and parent fields. + Set HAS_CHILDREN to tell whether the die has children or not. */ + +static gdb_byte * +read_full_die (const struct die_reader_specs *reader, + struct die_info **diep, gdb_byte *info_ptr, + int *has_children) +{ + return read_full_die_1 (reader, diep, info_ptr, has_children, 0); +} + +/* Abbreviation tables. + + 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 - in a hash table. This function also sets flags in CU describing - the data found in the abbrev table. */ + in a hash table. */ + +/* Allocate space for a struct abbrev_info object in ABBREV_TABLE. */ + +static struct abbrev_info * +abbrev_table_alloc_abbrev (struct abbrev_table *abbrev_table) +{ + struct abbrev_info *abbrev; + + abbrev = (struct abbrev_info *) + obstack_alloc (&abbrev_table->abbrev_obstack, sizeof (struct abbrev_info)); + memset (abbrev, 0, sizeof (struct abbrev_info)); + return abbrev; +} + +/* Add an abbreviation to the table. */ static void -dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu) +abbrev_table_add_abbrev (struct abbrev_table *abbrev_table, + unsigned int abbrev_number, + struct abbrev_info *abbrev) { - struct comp_unit_head *cu_header = &cu->header; + unsigned int hash_number; + + hash_number = abbrev_number % ABBREV_HASH_SIZE; + abbrev->next = abbrev_table->abbrevs[hash_number]; + abbrev_table->abbrevs[hash_number] = abbrev; +} + +/* Look up an abbrev in the table. + Returns NULL if the abbrev is not found. */ + +static struct abbrev_info * +abbrev_table_lookup_abbrev (const struct abbrev_table *abbrev_table, + unsigned int abbrev_number) +{ + unsigned int hash_number; + struct abbrev_info *abbrev; + + hash_number = abbrev_number % ABBREV_HASH_SIZE; + abbrev = abbrev_table->abbrevs[hash_number]; + + while (abbrev) + { + if (abbrev->number == abbrev_number) + return abbrev; + abbrev = abbrev->next; + } + return NULL; +} + +/* Read in an abbrev table. */ + +static struct abbrev_table * +abbrev_table_read_table (struct dwarf2_section_info *section, + sect_offset offset) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + bfd *abfd = section->asection->owner; + struct abbrev_table *abbrev_table; gdb_byte *abbrev_ptr; struct abbrev_info *cur_abbrev; unsigned int abbrev_number, bytes_read, abbrev_name; - unsigned int abbrev_form, hash_number; + unsigned int abbrev_form; struct attr_abbrev *cur_attrs; unsigned int allocated_attrs; - /* Initialize dwarf2 abbrevs. */ - obstack_init (&cu->abbrev_obstack); - cu->dwarf2_abbrevs = obstack_alloc (&cu->abbrev_obstack, - (ABBREV_HASH_SIZE - * sizeof (struct abbrev_info *))); - memset (cu->dwarf2_abbrevs, 0, - ABBREV_HASH_SIZE * sizeof (struct abbrev_info *)); - - dwarf2_read_section (dwarf2_per_objfile->objfile, - &dwarf2_per_objfile->abbrev); - abbrev_ptr = dwarf2_per_objfile->abbrev.buffer + cu_header->abbrev_offset; + abbrev_table = XMALLOC (struct abbrev_table); + abbrev_table->offset = offset; + obstack_init (&abbrev_table->abbrev_obstack); + abbrev_table->abbrevs = obstack_alloc (&abbrev_table->abbrev_obstack, + (ABBREV_HASH_SIZE + * sizeof (struct abbrev_info *))); + memset (abbrev_table->abbrevs, 0, + ABBREV_HASH_SIZE * sizeof (struct abbrev_info *)); + + dwarf2_read_section (objfile, section); + abbrev_ptr = section->buffer + offset.sect_off; abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; @@ -9399,7 +13159,7 @@ dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu) /* Loop until we reach an abbrev number of 0. */ while (abbrev_number) { - cur_abbrev = dwarf_alloc_abbrev (cu); + cur_abbrev = abbrev_table_alloc_abbrev (abbrev_table); /* read in abbrev header */ cur_abbrev->number = abbrev_number; @@ -9408,9 +13168,6 @@ dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu) cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr); abbrev_ptr += 1; - if (cur_abbrev->tag == DW_TAG_namespace) - cu->has_namespace_info = 1; - /* now read in declarations */ abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; @@ -9426,16 +13183,6 @@ dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu) * sizeof (struct attr_abbrev))); } - /* Record whether this compilation unit might have - inter-compilation-unit references. If we don't know what form - this attribute will have, then it might potentially be a - DW_FORM_ref_addr, so we conservatively expect inter-CU - references. */ - - if (abbrev_form == DW_FORM_ref_addr - || abbrev_form == DW_FORM_indirect) - cu->has_form_ref_addr = 1; - cur_attrs[cur_abbrev->num_attrs].name = abbrev_name; cur_attrs[cur_abbrev->num_attrs++].form = abbrev_form; abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); @@ -9444,15 +13191,13 @@ dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu) abbrev_ptr += bytes_read; } - cur_abbrev->attrs = obstack_alloc (&cu->abbrev_obstack, + cur_abbrev->attrs = obstack_alloc (&abbrev_table->abbrev_obstack, (cur_abbrev->num_attrs * sizeof (struct attr_abbrev))); memcpy (cur_abbrev->attrs, cur_attrs, cur_abbrev->num_attrs * sizeof (struct attr_abbrev)); - hash_number = abbrev_number % ABBREV_HASH_SIZE; - cur_abbrev->next = cu->dwarf2_abbrevs[hash_number]; - cu->dwarf2_abbrevs[hash_number] = cur_abbrev; + abbrev_table_add_abbrev (abbrev_table, abbrev_number, cur_abbrev); /* Get next abbreviation. Under Irix6 the abbreviations for a compilation unit are not @@ -9461,50 +13206,65 @@ dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu) already read (which means we are about to read the abbreviations for the next compile unit) or if the end of the abbreviation table is reached. */ - if ((unsigned int) (abbrev_ptr - dwarf2_per_objfile->abbrev.buffer) - >= dwarf2_per_objfile->abbrev.size) + if ((unsigned int) (abbrev_ptr - section->buffer) >= section->size) break; abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; - if (dwarf2_lookup_abbrev (abbrev_number, cu) != NULL) + if (abbrev_table_lookup_abbrev (abbrev_table, abbrev_number) != NULL) break; } xfree (cur_attrs); + return abbrev_table; } -/* Release the memory used by the abbrev table for a compilation unit. */ +/* Free the resources held by ABBREV_TABLE. */ static void -dwarf2_free_abbrev_table (void *ptr_to_cu) +abbrev_table_free (struct abbrev_table *abbrev_table) { - struct dwarf2_cu *cu = ptr_to_cu; - - obstack_free (&cu->abbrev_obstack, NULL); - cu->dwarf2_abbrevs = NULL; + obstack_free (&abbrev_table->abbrev_obstack, NULL); + xfree (abbrev_table); } -/* Lookup an abbrev_info structure in the abbrev hash table. */ +/* Same as abbrev_table_free but as a cleanup. + We pass in a pointer to the pointer to the table so that we can + set the pointer to NULL when we're done. It also simplifies + build_type_unit_groups. */ -static struct abbrev_info * -dwarf2_lookup_abbrev (unsigned int number, struct dwarf2_cu *cu) +static void +abbrev_table_free_cleanup (void *table_ptr) { - unsigned int hash_number; - struct abbrev_info *abbrev; + struct abbrev_table **abbrev_table_ptr = table_ptr; + + if (*abbrev_table_ptr != NULL) + abbrev_table_free (*abbrev_table_ptr); + *abbrev_table_ptr = NULL; +} - hash_number = number % ABBREV_HASH_SIZE; - abbrev = cu->dwarf2_abbrevs[hash_number]; +/* Read the abbrev table for CU from ABBREV_SECTION. */ - while (abbrev) - { - if (abbrev->number == number) - return abbrev; - else - abbrev = abbrev->next; - } - return NULL; +static void +dwarf2_read_abbrevs (struct dwarf2_cu *cu, + struct dwarf2_section_info *abbrev_section) +{ + cu->abbrev_table = + abbrev_table_read_table (abbrev_section, cu->header.abbrev_offset); } +/* Release the memory used by the abbrev table for a compilation unit. */ + +static void +dwarf2_free_abbrev_table (void *ptr_to_cu) +{ + struct dwarf2_cu *cu = ptr_to_cu; + + abbrev_table_free (cu->abbrev_table); + /* Set this to NULL so that we SEGV if we try to read it later, + and also because free_comp_unit verifies this is NULL. */ + cu->abbrev_table = NULL; +} + /* Returns nonzero if TAG represents a type that we might generate a partial symbol for. */ @@ -9540,21 +13300,23 @@ is_type_tag_for_partial (int tag) /* Load all DIEs that are interesting for partial symbols into memory. */ static struct partial_die_info * -load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, - int building_psymtab, struct dwarf2_cu *cu) +load_partial_dies (const struct die_reader_specs *reader, + gdb_byte *info_ptr, int building_psymtab) { + struct dwarf2_cu *cu = reader->cu; + struct objfile *objfile = cu->objfile; struct partial_die_info *part_die; struct partial_die_info *parent_die, *last_die, *first_die = NULL; struct abbrev_info *abbrev; unsigned int bytes_read; unsigned int load_all = 0; - int nesting_level = 1; parent_die = NULL; last_die = NULL; - if (cu->per_cu && cu->per_cu->load_all_dies) + gdb_assert (cu->per_cu != NULL); + if (cu->per_cu->load_all_dies) load_all = 1; cu->partial_dies @@ -9604,20 +13366,19 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, if (!load_all) { /* We don't need a partial DIE for the template argument. */ - info_ptr = skip_one_die (buffer, info_ptr + bytes_read, abbrev, - cu); + info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev); continue; } } - /* We only recurse into subprograms looking for template arguments. + /* We only recurse into c++ subprograms looking for template arguments. Skip their other children. */ if (!load_all && cu->language == language_cplus && parent_die != NULL && parent_die->tag == DW_TAG_subprogram) { - info_ptr = skip_one_die (buffer, info_ptr + bytes_read, abbrev, cu); + info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev); continue; } @@ -9634,15 +13395,16 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, && abbrev->tag != DW_TAG_variable && abbrev->tag != DW_TAG_namespace && abbrev->tag != DW_TAG_module - && abbrev->tag != DW_TAG_member) + && abbrev->tag != DW_TAG_member + && abbrev->tag != DW_TAG_imported_unit) { /* Otherwise we skip to the next sibling, if any. */ - info_ptr = skip_one_die (buffer, info_ptr + bytes_read, abbrev, cu); + info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev); continue; } - info_ptr = read_partial_die (part_die, abbrev, bytes_read, abfd, - buffer, info_ptr, cu); + info_ptr = read_partial_die (reader, part_die, abbrev, bytes_read, + info_ptr); /* This two-pass algorithm for processing partial symbols has a high cost in cache pressure. Thus, handle some simple cases @@ -9670,9 +13432,9 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, if (building_psymtab && part_die->name != NULL) add_psymbol_to_list (part_die->name, strlen (part_die->name), 0, VAR_DOMAIN, LOC_TYPEDEF, - &cu->objfile->static_psymbols, - 0, (CORE_ADDR) 0, cu->language, cu->objfile); - info_ptr = locate_pdi_sibling (part_die, buffer, info_ptr, abfd, cu); + &objfile->static_psymbols, + 0, (CORE_ADDR) 0, cu->language, objfile); + info_ptr = locate_pdi_sibling (reader, part_die, info_ptr); continue; } @@ -9688,7 +13450,7 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, complaint (&symfile_complaints, _("DW_TAG_typedef has childen - GCC PR debug/47510 bug " "- DIE at 0x%x [in module %s]"), - part_die->offset, cu->objfile->name); + part_die->offset.sect_off, objfile->name); /* If we're at the second level, and we're an enumerator, and our parent has no specification (meaning possibly lives in a @@ -9708,11 +13470,11 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, VAR_DOMAIN, LOC_CONST, (cu->language == language_cplus || cu->language == language_java) - ? &cu->objfile->global_psymbols - : &cu->objfile->static_psymbols, - 0, (CORE_ADDR) 0, cu->language, cu->objfile); + ? &objfile->global_psymbols + : &objfile->static_psymbols, + 0, (CORE_ADDR) 0, cu->language, objfile); - info_ptr = locate_pdi_sibling (part_die, buffer, info_ptr, abfd, cu); + info_ptr = locate_pdi_sibling (reader, part_die, info_ptr); continue; } @@ -9762,7 +13524,7 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, void **slot; slot = htab_find_slot_with_hash (cu->partial_dies, part_die, - part_die->offset, INSERT); + part_die->offset.sect_off, INSERT); *slot = part_die; } @@ -9805,7 +13567,7 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, } /* Otherwise we skip to the next sibling, if any. */ - info_ptr = locate_pdi_sibling (last_die, buffer, info_ptr, abfd, cu); + info_ptr = locate_pdi_sibling (reader, last_die, info_ptr); /* Back to the top, do it again. */ } @@ -9814,20 +13576,23 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr, /* Read a minimal amount of information into the minimal die structure. */ static gdb_byte * -read_partial_die (struct partial_die_info *part_die, - struct abbrev_info *abbrev, - unsigned int abbrev_len, bfd *abfd, - gdb_byte *buffer, gdb_byte *info_ptr, - struct dwarf2_cu *cu) +read_partial_die (const struct die_reader_specs *reader, + struct partial_die_info *part_die, + struct abbrev_info *abbrev, unsigned int abbrev_len, + gdb_byte *info_ptr) { + struct dwarf2_cu *cu = reader->cu; + struct objfile *objfile = cu->objfile; + gdb_byte *buffer = reader->buffer; unsigned int i; struct attribute attr; int has_low_pc_attr = 0; int has_high_pc_attr = 0; + int high_pc_relative = 0; memset (part_die, 0, sizeof (struct partial_die_info)); - part_die->offset = info_ptr - buffer; + part_die->offset.sect_off = info_ptr - buffer; info_ptr += abbrev_len; @@ -9839,7 +13604,7 @@ read_partial_die (struct partial_die_info *part_die, for (i = 0; i < abbrev->num_attrs; ++i) { - info_ptr = read_attribute (&attr, &abbrev->attrs[i], abfd, info_ptr, cu); + info_ptr = read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr); /* Store the data if it is of an attribute we want to keep in a partial symbol table. */ @@ -9849,6 +13614,7 @@ read_partial_die (struct partial_die_info *part_die, switch (part_die->tag) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: case DW_TAG_type_unit: /* Compilation units have a DW_AT_name that is a filename, not a source language identifier. */ @@ -9861,7 +13627,7 @@ read_partial_die (struct partial_die_info *part_die, default: part_die->name = dwarf2_canonicalize_name (DW_STRING (&attr), cu, - &cu->objfile->objfile_obstack); + &objfile->objfile_obstack); break; } break; @@ -9880,13 +13646,20 @@ read_partial_die (struct partial_die_info *part_die, break; case DW_AT_high_pc: has_high_pc_attr = 1; - part_die->highpc = DW_ADDR (&attr); + if (attr.form == DW_FORM_addr + || attr.form == DW_FORM_GNU_addr_index) + part_die->highpc = DW_ADDR (&attr); + else + { + high_pc_relative = 1; + part_die->highpc = DW_UNSND (&attr); + } break; case DW_AT_location: /* Support the .debug_loc offsets. */ if (attr_form_is_block (&attr)) { - part_die->locdesc = DW_BLOCK (&attr); + part_die->d.locdesc = DW_BLOCK (&attr); } else if (attr_form_is_section_offset (&attr)) { @@ -9912,6 +13685,8 @@ read_partial_die (struct partial_die_info *part_die, case DW_AT_extension: part_die->has_specification = 1; part_die->spec_offset = dwarf2_get_ref_die_offset (&attr); + part_die->spec_is_dwz = (attr.form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz); break; case DW_AT_sibling: /* Ignore absolute siblings, they might point outside of @@ -9920,7 +13695,7 @@ read_partial_die (struct partial_die_info *part_die, complaint (&symfile_complaints, _("ignoring absolute DW_AT_sibling")); else - part_die->sibling = buffer + dwarf2_get_ref_die_offset (&attr); + part_die->sibling = buffer + dwarf2_get_ref_die_offset (&attr).sect_off; break; case DW_AT_byte_size: part_die->has_byte_size = 1; @@ -9950,11 +13725,29 @@ read_partial_die (struct partial_die_info *part_die, language_of_main = language_fortran; } break; + case DW_AT_inline: + if (DW_UNSND (&attr) == DW_INL_inlined + || DW_UNSND (&attr) == DW_INL_declared_inlined) + part_die->may_be_inlined = 1; + break; + + case DW_AT_import: + if (part_die->tag == DW_TAG_imported_unit) + { + part_die->d.offset = dwarf2_get_ref_die_offset (&attr); + part_die->is_dwz = (attr.form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz); + } + break; + default: break; } } + if (high_pc_relative) + part_die->highpc += part_die->lowpc; + if (has_low_pc_attr && has_high_pc_attr) { /* When using the GNU linker, .gnu.linkonce. sections are used to @@ -9967,25 +13760,25 @@ read_partial_die (struct partial_die_info *part_die, so that GDB will ignore it. */ if (part_die->lowpc == 0 && !dwarf2_per_objfile->has_section_at_zero) { - struct gdbarch *gdbarch = get_objfile_arch (cu->objfile); + struct gdbarch *gdbarch = get_objfile_arch (objfile); complaint (&symfile_complaints, _("DW_AT_low_pc %s is zero " "for DIE at 0x%x [in module %s]"), paddress (gdbarch, part_die->lowpc), - part_die->offset, cu->objfile->name); + part_die->offset.sect_off, objfile->name); } /* dwarf2_get_pc_bounds has also the strict low < high requirement. */ else if (part_die->lowpc >= part_die->highpc) { - struct gdbarch *gdbarch = get_objfile_arch (cu->objfile); + struct gdbarch *gdbarch = get_objfile_arch (objfile); complaint (&symfile_complaints, _("DW_AT_low_pc %s is not < DW_AT_high_pc %s " "for DIE at 0x%x [in module %s]"), paddress (gdbarch, part_die->lowpc), paddress (gdbarch, part_die->highpc), - part_die->offset, cu->objfile->name); + part_die->offset.sect_off, objfile->name); } else part_die->has_pc_info = 1; @@ -9997,13 +13790,14 @@ read_partial_die (struct partial_die_info *part_die, /* Find a cached partial DIE at OFFSET in CU. */ static struct partial_die_info * -find_partial_die_in_comp_unit (unsigned int offset, struct dwarf2_cu *cu) +find_partial_die_in_comp_unit (sect_offset offset, struct dwarf2_cu *cu) { struct partial_die_info *lookup_die = NULL; struct partial_die_info part_die; part_die.offset = offset; - lookup_die = htab_find_with_hash (cu->partial_dies, &part_die, offset); + lookup_die = htab_find_with_hash (cu->partial_dies, &part_die, + offset.sect_off); return lookup_die; } @@ -10014,75 +13808,65 @@ find_partial_die_in_comp_unit (unsigned int offset, struct dwarf2_cu *cu) DW_FORM_ref_sig8). */ static struct partial_die_info * -find_partial_die (unsigned int offset, struct dwarf2_cu *cu) +find_partial_die (sect_offset offset, int offset_in_dwz, struct dwarf2_cu *cu) { + struct objfile *objfile = cu->objfile; struct dwarf2_per_cu_data *per_cu = NULL; struct partial_die_info *pd = NULL; - if (cu->per_cu->debug_types_section) + if (offset_in_dwz == cu->per_cu->is_dwz + && offset_in_cu_p (&cu->header, offset)) { pd = find_partial_die_in_comp_unit (offset, cu); if (pd != NULL) return pd; - goto not_found; + /* We missed recording what we needed. + Load all dies and try again. */ + per_cu = cu->per_cu; } - - if (offset_in_cu_p (&cu->header, offset)) + else { - pd = find_partial_die_in_comp_unit (offset, cu); - if (pd != NULL) - return pd; - } + /* TUs don't reference other CUs/TUs (except via type signatures). */ + if (cu->per_cu->is_debug_types) + { + error (_("Dwarf Error: Type Unit at offset 0x%lx contains" + " external reference to offset 0x%lx [in module %s].\n"), + (long) cu->header.offset.sect_off, (long) offset.sect_off, + bfd_get_filename (objfile->obfd)); + } + per_cu = dwarf2_find_containing_comp_unit (offset, offset_in_dwz, + objfile); - per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile); + if (per_cu->cu == NULL || per_cu->cu->partial_dies == NULL) + load_partial_comp_unit (per_cu); - if (per_cu->cu == NULL || per_cu->cu->partial_dies == NULL) - load_partial_comp_unit (per_cu, cu->objfile); + per_cu->cu->last_used = 0; + pd = find_partial_die_in_comp_unit (offset, per_cu->cu); + } - per_cu->cu->last_used = 0; - pd = find_partial_die_in_comp_unit (offset, per_cu->cu); + /* If we didn't find it, and not all dies have been loaded, + load them all and try again. */ if (pd == NULL && per_cu->load_all_dies == 0) { - struct cleanup *back_to; - struct partial_die_info comp_unit_die; - struct abbrev_info *abbrev; - unsigned int bytes_read; - char *info_ptr; - per_cu->load_all_dies = 1; - /* Re-read the DIEs. */ - back_to = make_cleanup (null_cleanup, 0); - if (per_cu->cu->dwarf2_abbrevs == NULL) - { - dwarf2_read_abbrevs (per_cu->cu->objfile->obfd, per_cu->cu); - make_cleanup (dwarf2_free_abbrev_table, per_cu->cu); - } - info_ptr = (dwarf2_per_objfile->info.buffer - + per_cu->cu->header.offset - + per_cu->cu->header.first_die_offset); - abbrev = peek_die_abbrev (info_ptr, &bytes_read, per_cu->cu); - info_ptr = read_partial_die (&comp_unit_die, abbrev, bytes_read, - per_cu->cu->objfile->obfd, - dwarf2_per_objfile->info.buffer, info_ptr, - per_cu->cu); - if (comp_unit_die.has_children) - load_partial_dies (per_cu->cu->objfile->obfd, - dwarf2_per_objfile->info.buffer, info_ptr, - 0, per_cu->cu); - do_cleanups (back_to); + /* This is nasty. When we reread the DIEs, somewhere up the call chain + THIS_CU->cu may already be in use. So we can't just free it and + replace its DIEs with the ones we read in. Instead, we leave those + DIEs alone (which can still be in use, e.g. in scan_partial_symbols), + and clobber THIS_CU->cu->partial_dies with the hash table for the new + set. */ + load_partial_comp_unit (per_cu); pd = find_partial_die_in_comp_unit (offset, per_cu->cu); } - not_found: - if (pd == NULL) internal_error (__FILE__, __LINE__, _("could not find partial DIE 0x%x " "in cache [from module %s]\n"), - offset, bfd_get_filename (cu->objfile->obfd)); + offset.sect_off, bfd_get_filename (objfile->obfd)); return pd; } @@ -10109,7 +13893,8 @@ guess_partial_die_structure_name (struct partial_die_info *struct_pdi, real_pdi = struct_pdi; while (real_pdi->has_specification) - real_pdi = find_partial_die (real_pdi->spec_offset, cu); + real_pdi = find_partial_die (real_pdi->spec_offset, + real_pdi->spec_is_dwz, cu); if (real_pdi->die_parent != NULL) return; @@ -10127,9 +13912,9 @@ guess_partial_die_structure_name (struct partial_die_info *struct_pdi, if (actual_class_name != NULL) { struct_pdi->name - = obsavestring (actual_class_name, - strlen (actual_class_name), - &cu->objfile->objfile_obstack); + = obstack_copy0 (&cu->objfile->objfile_obstack, + actual_class_name, + strlen (actual_class_name)); xfree (actual_class_name); } break; @@ -10157,7 +13942,8 @@ fixup_partial_die (struct partial_die_info *part_die, { struct partial_die_info *spec_die; - spec_die = find_partial_die (part_die->spec_offset, cu); + spec_die = find_partial_die (part_die->spec_offset, + part_die->spec_is_dwz, cu); fixup_partial_die (spec_die, cu); @@ -10178,9 +13964,7 @@ fixup_partial_die (struct partial_die_info *part_die, /* If there is no parent die to provide a namespace, and there are children, see if we can determine the namespace from their linkage - name. - NOTE: We need to do this even if cu->has_namespace_info != 0. - gcc-4.5 -gdwarf-4 can drop the enclosing namespace. */ + name. */ if (cu->language == language_cplus && !VEC_empty (dwarf2_section_info_def, dwarf2_per_objfile->types) && part_die->die_parent == NULL @@ -10214,8 +13998,8 @@ fixup_partial_die (struct partial_die_info *part_die, else base = demangled; - part_die->name = obsavestring (base, strlen (base), - &cu->objfile->objfile_obstack); + part_die->name = obstack_copy0 (&cu->objfile->objfile_obstack, + base, strlen (base)); xfree (demangled); } } @@ -10226,10 +14010,12 @@ fixup_partial_die (struct partial_die_info *part_die, /* Read an attribute value described by an attribute form. */ static gdb_byte * -read_attribute_value (struct attribute *attr, unsigned form, - bfd *abfd, gdb_byte *info_ptr, - struct dwarf2_cu *cu) +read_attribute_value (const struct die_reader_specs *reader, + struct attribute *attr, unsigned form, + gdb_byte *info_ptr) { + struct dwarf2_cu *cu = reader->cu; + bfd *abfd = reader->abfd; struct comp_unit_head *cu_header = &cu->header; unsigned int bytes_read; struct dwarf_block *blk; @@ -10239,10 +14025,14 @@ read_attribute_value (struct attribute *attr, unsigned form, { case DW_FORM_ref_addr: if (cu->header.version == 2) - DW_ADDR (attr) = read_address (abfd, info_ptr, cu, &bytes_read); + DW_UNSND (attr) = read_address (abfd, info_ptr, cu, &bytes_read); else - DW_ADDR (attr) = read_offset (abfd, info_ptr, - &cu->header, &bytes_read); + DW_UNSND (attr) = read_offset (abfd, info_ptr, + &cu->header, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_GNU_ref_alt: + DW_UNSND (attr) = read_offset (abfd, info_ptr, &cu->header, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_addr: @@ -10287,10 +14077,25 @@ read_attribute_value (struct attribute *attr, unsigned form, info_ptr += bytes_read; break; case DW_FORM_strp: - DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header, - &bytes_read); - DW_STRING_IS_CANONICAL (attr) = 0; - info_ptr += bytes_read; + if (!cu->per_cu->is_dwz) + { + DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header, + &bytes_read); + DW_STRING_IS_CANONICAL (attr) = 0; + info_ptr += bytes_read; + break; + } + /* FALLTHROUGH */ + case DW_FORM_GNU_strp_alt: + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + LONGEST str_offset = read_offset (abfd, info_ptr, cu_header, + &bytes_read); + + DW_STRING (attr) = read_indirect_string_from_dwz (dwz, str_offset); + DW_STRING_IS_CANONICAL (attr) = 0; + info_ptr += bytes_read; + } break; case DW_FORM_exprloc: case DW_FORM_block: @@ -10329,19 +14134,23 @@ read_attribute_value (struct attribute *attr, unsigned form, info_ptr += bytes_read; break; case DW_FORM_ref1: - DW_ADDR (attr) = cu->header.offset + read_1_byte (abfd, info_ptr); + DW_UNSND (attr) = (cu->header.offset.sect_off + + read_1_byte (abfd, info_ptr)); info_ptr += 1; break; case DW_FORM_ref2: - DW_ADDR (attr) = cu->header.offset + read_2_bytes (abfd, info_ptr); + DW_UNSND (attr) = (cu->header.offset.sect_off + + read_2_bytes (abfd, info_ptr)); info_ptr += 2; break; case DW_FORM_ref4: - DW_ADDR (attr) = cu->header.offset + read_4_bytes (abfd, info_ptr); + DW_UNSND (attr) = (cu->header.offset.sect_off + + read_4_bytes (abfd, info_ptr)); info_ptr += 4; break; case DW_FORM_ref8: - DW_ADDR (attr) = cu->header.offset + read_8_bytes (abfd, info_ptr); + DW_UNSND (attr) = (cu->header.offset.sect_off + + read_8_bytes (abfd, info_ptr)); info_ptr += 8; break; case DW_FORM_ref_sig8: @@ -10349,18 +14158,48 @@ read_attribute_value (struct attribute *attr, unsigned form, for later lookup. NOTE: This is NULL if the type wasn't found. */ DW_SIGNATURED_TYPE (attr) = - lookup_signatured_type (cu->objfile, read_8_bytes (abfd, info_ptr)); + lookup_signatured_type (read_8_bytes (abfd, info_ptr)); info_ptr += 8; break; case DW_FORM_ref_udata: - DW_ADDR (attr) = (cu->header.offset - + read_unsigned_leb128 (abfd, info_ptr, &bytes_read)); + DW_UNSND (attr) = (cu->header.offset.sect_off + + read_unsigned_leb128 (abfd, info_ptr, &bytes_read)); info_ptr += bytes_read; break; case DW_FORM_indirect: form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; - info_ptr = read_attribute_value (attr, form, abfd, info_ptr, cu); + info_ptr = read_attribute_value (reader, attr, form, info_ptr); + break; + case DW_FORM_GNU_addr_index: + if (reader->dwo_file == NULL) + { + /* For now flag a hard error. + Later we can turn this into a complaint. */ + error (_("Dwarf Error: %s found in non-DWO CU [in module %s]"), + dwarf_form_name (form), + bfd_get_filename (abfd)); + } + DW_ADDR (attr) = read_addr_index_from_leb128 (cu, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_GNU_str_index: + if (reader->dwo_file == NULL) + { + /* For now flag a hard error. + Later we can turn this into a complaint if warranted. */ + error (_("Dwarf Error: %s found in non-DWO CU [in module %s]"), + dwarf_form_name (form), + bfd_get_filename (abfd)); + } + { + ULONGEST str_index = + read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + + DW_STRING (attr) = read_str_index (reader, cu, str_index); + DW_STRING_IS_CANONICAL (attr) = 0; + info_ptr += bytes_read; + } break; default: error (_("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]"), @@ -10368,6 +14207,10 @@ read_attribute_value (struct attribute *attr, unsigned form, bfd_get_filename (abfd)); } + /* Super hack. */ + if (cu->per_cu->is_dwz && is_ref_attr (attr)) + attr->form = DW_FORM_GNU_ref_alt; + /* We have seen instances where the compiler tried to emit a byte size attribute of -1 which ended up being encoded as an unsigned 0xffffffff. Although 0xffffffff is technically a valid size value, @@ -10391,53 +14234,54 @@ read_attribute_value (struct attribute *attr, unsigned form, /* Read an attribute described by an abbreviated attribute. */ static gdb_byte * -read_attribute (struct attribute *attr, struct attr_abbrev *abbrev, - bfd *abfd, gdb_byte *info_ptr, struct dwarf2_cu *cu) +read_attribute (const struct die_reader_specs *reader, + struct attribute *attr, struct attr_abbrev *abbrev, + gdb_byte *info_ptr) { attr->name = abbrev->name; - return read_attribute_value (attr, abbrev->form, abfd, info_ptr, cu); + return read_attribute_value (reader, attr, abbrev->form, info_ptr); } /* Read dwarf information from a buffer. */ static unsigned int -read_1_byte (bfd *abfd, gdb_byte *buf) +read_1_byte (bfd *abfd, const gdb_byte *buf) { return bfd_get_8 (abfd, buf); } static int -read_1_signed_byte (bfd *abfd, gdb_byte *buf) +read_1_signed_byte (bfd *abfd, const gdb_byte *buf) { return bfd_get_signed_8 (abfd, buf); } static unsigned int -read_2_bytes (bfd *abfd, gdb_byte *buf) +read_2_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_16 (abfd, buf); } static int -read_2_signed_bytes (bfd *abfd, gdb_byte *buf) +read_2_signed_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_signed_16 (abfd, buf); } static unsigned int -read_4_bytes (bfd *abfd, gdb_byte *buf) +read_4_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_32 (abfd, buf); } static int -read_4_signed_bytes (bfd *abfd, gdb_byte *buf) +read_4_signed_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_signed_32 (abfd, buf); } static ULONGEST -read_8_bytes (bfd *abfd, gdb_byte *buf) +read_8_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_64 (abfd, buf); } @@ -10663,6 +14507,30 @@ read_indirect_string_at_offset (bfd *abfd, LONGEST str_offset) return (char *) (dwarf2_per_objfile->str.buffer + str_offset); } +/* Read a string at offset STR_OFFSET in the .debug_str section from + the .dwz file DWZ. Throw an error if the offset is too large. If + the string consists of a single NUL byte, return NULL; otherwise + return a pointer to the string. */ + +static char * +read_indirect_string_from_dwz (struct dwz_file *dwz, LONGEST str_offset) +{ + dwarf2_read_section (dwarf2_per_objfile->objfile, &dwz->str); + + if (dwz->str.buffer == NULL) + error (_("DW_FORM_GNU_strp_alt used without .debug_str " + "section [in module %s]"), + bfd_get_filename (dwz->dwz_bfd)); + if (str_offset >= dwz->str.size) + error (_("DW_FORM_GNU_strp_alt pointing outside of " + ".debug_str section [in module %s]"), + bfd_get_filename (dwz->dwz_bfd)); + gdb_assert (HOST_CHAR_BIT == 8); + if (dwz->str.buffer[str_offset] == '\0') + return NULL; + return (char *) (dwz->str.buffer + str_offset); +} + static char * read_indirect_string (bfd *abfd, gdb_byte *buf, const struct comp_unit_head *cu_header, @@ -10673,10 +14541,10 @@ read_indirect_string (bfd *abfd, gdb_byte *buf, return read_indirect_string_at_offset (abfd, str_offset); } -static unsigned long +static ULONGEST read_unsigned_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) { - unsigned long result; + ULONGEST result; unsigned int num_read; int i, shift; unsigned char byte; @@ -10690,7 +14558,7 @@ read_unsigned_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) byte = bfd_get_8 (abfd, buf); buf++; num_read++; - result |= ((unsigned long)(byte & 127) << shift); + result |= ((ULONGEST) (byte & 127) << shift); if ((byte & 128) == 0) { break; @@ -10701,10 +14569,10 @@ read_unsigned_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) return result; } -static long +static LONGEST read_signed_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) { - long result; + LONGEST result; int i, shift, num_read; unsigned char byte; @@ -10717,7 +14585,7 @@ read_signed_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) byte = bfd_get_8 (abfd, buf); buf++; num_read++; - result |= ((long)(byte & 127) << shift); + result |= ((LONGEST) (byte & 127) << shift); shift += 7; if ((byte & 128) == 0) { @@ -10725,24 +14593,190 @@ read_signed_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) } } if ((shift < 8 * sizeof (result)) && (byte & 0x40)) - result |= -(((long)1) << shift); + result |= -(((LONGEST) 1) << shift); *bytes_read_ptr = num_read; return result; } -/* Return a pointer to just past the end of an LEB128 number in BUF. */ +/* Given index ADDR_INDEX in .debug_addr, fetch the value. + ADDR_BASE is the DW_AT_GNU_addr_base attribute or zero. + ADDR_SIZE is the size of addresses from the CU header. */ + +static CORE_ADDR +read_addr_index_1 (unsigned int addr_index, ULONGEST addr_base, int addr_size) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + bfd *abfd = objfile->obfd; + const gdb_byte *info_ptr; + + dwarf2_read_section (objfile, &dwarf2_per_objfile->addr); + if (dwarf2_per_objfile->addr.buffer == NULL) + error (_("DW_FORM_addr_index used without .debug_addr section [in module %s]"), + objfile->name); + if (addr_base + addr_index * addr_size >= dwarf2_per_objfile->addr.size) + error (_("DW_FORM_addr_index pointing outside of " + ".debug_addr section [in module %s]"), + objfile->name); + info_ptr = (dwarf2_per_objfile->addr.buffer + + addr_base + addr_index * addr_size); + if (addr_size == 4) + return bfd_get_32 (abfd, info_ptr); + else + return bfd_get_64 (abfd, info_ptr); +} + +/* Given index ADDR_INDEX in .debug_addr, fetch the value. */ + +static CORE_ADDR +read_addr_index (struct dwarf2_cu *cu, unsigned int addr_index) +{ + return read_addr_index_1 (addr_index, cu->addr_base, cu->header.addr_size); +} + +/* Given a pointer to an leb128 value, fetch the value from .debug_addr. */ + +static CORE_ADDR +read_addr_index_from_leb128 (struct dwarf2_cu *cu, gdb_byte *info_ptr, + unsigned int *bytes_read) +{ + bfd *abfd = cu->objfile->obfd; + unsigned int addr_index = read_unsigned_leb128 (abfd, info_ptr, bytes_read); + + return read_addr_index (cu, addr_index); +} + +/* Data structure to pass results from dwarf2_read_addr_index_reader + back to dwarf2_read_addr_index. */ + +struct dwarf2_read_addr_index_data +{ + ULONGEST addr_base; + int addr_size; +}; + +/* die_reader_func for dwarf2_read_addr_index. */ + +static void +dwarf2_read_addr_index_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data) +{ + struct dwarf2_cu *cu = reader->cu; + struct dwarf2_read_addr_index_data *aidata = + (struct dwarf2_read_addr_index_data *) data; + + aidata->addr_base = cu->addr_base; + aidata->addr_size = cu->header.addr_size; +} + +/* Given an index in .debug_addr, fetch the value. + NOTE: This can be called during dwarf expression evaluation, + long after the debug information has been read, and thus per_cu->cu + may no longer exist. */ + +CORE_ADDR +dwarf2_read_addr_index (struct dwarf2_per_cu_data *per_cu, + unsigned int addr_index) +{ + struct objfile *objfile = per_cu->objfile; + struct dwarf2_cu *cu = per_cu->cu; + ULONGEST addr_base; + int addr_size; + + /* This is intended to be called from outside this file. */ + dw2_setup (objfile); + + /* We need addr_base and addr_size. + If we don't have PER_CU->cu, we have to get it. + Nasty, but the alternative is storing the needed info in PER_CU, + which at this point doesn't seem justified: it's not clear how frequently + it would get used and it would increase the size of every PER_CU. + Entry points like dwarf2_per_cu_addr_size do a similar thing + so we're not in uncharted territory here. + Alas we need to be a bit more complicated as addr_base is contained + in the DIE. + + We don't need to read the entire CU(/TU). + We just need the header and top level die. + + IWBN to use the aging mechanism to let us lazily later discard the CU. + For now we skip this optimization. */ + + if (cu != NULL) + { + addr_base = cu->addr_base; + addr_size = cu->header.addr_size; + } + else + { + struct dwarf2_read_addr_index_data aidata; + + /* Note: We can't use init_cutu_and_read_dies_simple here, + we need addr_base. */ + init_cutu_and_read_dies (per_cu, NULL, 0, 0, + dwarf2_read_addr_index_reader, &aidata); + addr_base = aidata.addr_base; + addr_size = aidata.addr_size; + } + + return read_addr_index_1 (addr_index, addr_base, addr_size); +} + +/* Given a DW_AT_str_index, fetch the string. */ + +static char * +read_str_index (const struct die_reader_specs *reader, + struct dwarf2_cu *cu, ULONGEST str_index) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + const char *dwo_name = objfile->name; + bfd *abfd = objfile->obfd; + struct dwo_sections *sections = &reader->dwo_file->sections; + gdb_byte *info_ptr; + ULONGEST str_offset; + + dwarf2_read_section (objfile, §ions->str); + dwarf2_read_section (objfile, §ions->str_offsets); + if (sections->str.buffer == NULL) + error (_("DW_FORM_str_index used without .debug_str.dwo section" + " in CU at offset 0x%lx [in module %s]"), + (long) cu->header.offset.sect_off, dwo_name); + if (sections->str_offsets.buffer == NULL) + error (_("DW_FORM_str_index used without .debug_str_offsets.dwo section" + " in CU at offset 0x%lx [in module %s]"), + (long) cu->header.offset.sect_off, dwo_name); + if (str_index * cu->header.offset_size >= sections->str_offsets.size) + error (_("DW_FORM_str_index pointing outside of .debug_str_offsets.dwo" + " section in CU at offset 0x%lx [in module %s]"), + (long) cu->header.offset.sect_off, dwo_name); + info_ptr = (sections->str_offsets.buffer + + str_index * cu->header.offset_size); + if (cu->header.offset_size == 4) + str_offset = bfd_get_32 (abfd, info_ptr); + else + str_offset = bfd_get_64 (abfd, info_ptr); + if (str_offset >= sections->str.size) + error (_("Offset from DW_FORM_str_index pointing outside of" + " .debug_str.dwo section in CU at offset 0x%lx [in module %s]"), + (long) cu->header.offset.sect_off, dwo_name); + return (char *) (sections->str.buffer + str_offset); +} + +/* Return the length of an LEB128 number in BUF. */ -static gdb_byte * -skip_leb128 (bfd *abfd, gdb_byte *buf) +static int +leb128_size (const gdb_byte *buf) { - int byte; + const gdb_byte *begin = buf; + gdb_byte byte; while (1) { - byte = bfd_get_8 (abfd, buf); - buf++; + byte = *buf++; if ((byte & 128) == 0) - return buf; + return buf - begin; } } @@ -10767,6 +14801,9 @@ set_cu_language (unsigned int lang, struct dwarf2_cu *cu) case DW_LANG_Fortran95: cu->language = language_fortran; break; + case DW_LANG_Go: + cu->language = language_go; + break; case DW_LANG_Mips_Assembler: cu->language = language_asm; break; @@ -10800,22 +14837,24 @@ set_cu_language (unsigned int lang, struct dwarf2_cu *cu) static struct attribute * dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu) { - unsigned int i; - struct attribute *spec = NULL; - - for (i = 0; i < die->num_attrs; ++i) + for (;;) { - if (die->attrs[i].name == name) - return &die->attrs[i]; - if (die->attrs[i].name == DW_AT_specification - || die->attrs[i].name == DW_AT_abstract_origin) - spec = &die->attrs[i]; - } + unsigned int i; + struct attribute *spec = NULL; + + for (i = 0; i < die->num_attrs; ++i) + { + if (die->attrs[i].name == name) + return &die->attrs[i]; + if (die->attrs[i].name == DW_AT_specification + || die->attrs[i].name == DW_AT_abstract_origin) + spec = &die->attrs[i]; + } + + if (!spec) + break; - if (spec) - { die = follow_die_ref (die, spec, &cu); - return dwarf2_attr (die, name, cu); } return NULL; @@ -10828,8 +14867,7 @@ dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu) back up the chain, and we want to go down. */ static struct attribute * -dwarf2_attr_no_follow (struct die_info *die, unsigned int name, - struct dwarf2_cu *cu) +dwarf2_attr_no_follow (struct die_info *die, unsigned int name) { unsigned int i; @@ -10967,17 +15005,40 @@ add_file_name (struct line_header *lh, fe->symtab = NULL; } +/* A convenience function to find the proper .debug_line section for a + CU. */ + +static struct dwarf2_section_info * +get_debug_line_section (struct dwarf2_cu *cu) +{ + struct dwarf2_section_info *section; + + /* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the + DWO file. */ + if (cu->dwo_unit && cu->per_cu->is_debug_types) + section = &cu->dwo_unit->dwo_file->sections.line; + else if (cu->per_cu->is_dwz) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + section = &dwz->line; + } + else + section = &dwarf2_per_objfile->line; + + return section; +} + /* Read the statement program header starting at OFFSET in - .debug_line, according to the endianness of ABFD. Return a pointer + .debug_line, or .debug_line.dwo. Return a pointer to a struct line_header, allocated using xmalloc. NOTE: the strings in the include directory and file name tables of - the returned object point into debug_line_buffer, and must not be - freed. */ + the returned object point into the dwarf line section buffer, + and must not be freed. */ static struct line_header * -dwarf_decode_line_header (unsigned int offset, bfd *abfd, - struct dwarf2_cu *cu) +dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) { struct cleanup *back_to; struct line_header *lh; @@ -10985,17 +15046,27 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd, unsigned int bytes_read, offset_size; int i; char *cur_dir, *cur_file; + struct dwarf2_section_info *section; + bfd *abfd; - dwarf2_read_section (dwarf2_per_objfile->objfile, &dwarf2_per_objfile->line); - if (dwarf2_per_objfile->line.buffer == NULL) + section = get_debug_line_section (cu); + dwarf2_read_section (dwarf2_per_objfile->objfile, section); + if (section->buffer == NULL) { - complaint (&symfile_complaints, _("missing .debug_line section")); + if (cu->dwo_unit && cu->per_cu->is_debug_types) + complaint (&symfile_complaints, _("missing .debug_line.dwo section")); + else + complaint (&symfile_complaints, _("missing .debug_line section")); return 0; } + /* We can't do this until we know the section is non-empty. + Only then do we know we have such a section. */ + abfd = section->asection->owner; + /* Make sure that at least there's room for the total_length field. That could be 12 bytes long, but we're just going to fudge that. */ - if (offset + 4 >= dwarf2_per_objfile->line.size) + if (offset + 4 >= section->size) { dwarf2_statement_list_fits_in_line_number_section_complaint (); return 0; @@ -11006,15 +15077,14 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd, back_to = make_cleanup ((make_cleanup_ftype *) free_line_header, (void *) lh); - line_ptr = dwarf2_per_objfile->line.buffer + offset; + line_ptr = section->buffer + offset; /* Read in the header. */ lh->total_length = read_checked_initial_length_and_offset (abfd, line_ptr, &cu->header, &bytes_read, &offset_size); line_ptr += bytes_read; - if (line_ptr + lh->total_length > (dwarf2_per_objfile->line.buffer - + dwarf2_per_objfile->line.size)) + if (line_ptr + lh->total_length > (section->buffer + section->size)) { dwarf2_statement_list_fits_in_line_number_section_complaint (); return 0; @@ -11086,8 +15156,7 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd, line_ptr += bytes_read; lh->statement_program_start = line_ptr; - if (line_ptr > (dwarf2_per_objfile->line.buffer - + dwarf2_per_objfile->line.size)) + if (line_ptr > (section->buffer + section->size)) complaint (&symfile_complaints, _("line number info header doesn't " "fit in `.debug_line' section")); @@ -11096,58 +15165,14 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd, return lh; } -/* This function exists to work around a bug in certain compilers - (particularly GCC 2.95), in which the first line number marker of a - function does not show up until after the prologue, right before - the second line number marker. This function shifts ADDRESS down - to the beginning of the function if necessary, and is called on - addresses passed to record_line. */ - -static CORE_ADDR -check_cu_functions (CORE_ADDR address, struct dwarf2_cu *cu) -{ - struct function_range *fn; - - /* Find the function_range containing address. */ - if (!cu->first_fn) - return address; - - if (!cu->cached_fn) - cu->cached_fn = cu->first_fn; - - fn = cu->cached_fn; - while (fn) - if (fn->lowpc <= address && fn->highpc > address) - goto found; - else - fn = fn->next; - - fn = cu->first_fn; - while (fn && fn != cu->cached_fn) - if (fn->lowpc <= address && fn->highpc > address) - goto found; - else - fn = fn->next; - - return address; - - found: - if (fn->seen_line) - return address; - if (address != fn->lowpc) - complaint (&symfile_complaints, - _("misplaced first line number at 0x%lx for '%s'"), - (unsigned long) address, fn->name); - fn->seen_line = 1; - return fn->lowpc; -} - /* Subroutine of dwarf_decode_lines to simplify it. Return the file name of the psymtab for included file FILE_INDEX in line header LH of PST. COMP_DIR is the compilation directory (DW_AT_comp_dir) or NULL if unknown. If space for the result is malloc'd, it will be freed by a cleanup. - Returns NULL if FILE_INDEX should be ignored, i.e., it is pst->filename. */ + Returns NULL if FILE_INDEX should be ignored, i.e., it is pst->filename. + + The function creates dangling cleanup registration. */ static char * psymtab_include_file_name (const struct line_header *lh, int file_index, @@ -11321,8 +15346,7 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, last_subfile = current_subfile; } /* Append row to matrix using current values. */ - addr = check_cu_functions (address, cu); - addr = gdbarch_addr_bits_remove (gdbarch, addr); + addr = gdbarch_addr_bits_remove (gdbarch, address); (*p_record_line) (current_subfile, line, addr); } } @@ -11352,12 +15376,12 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, GCd by the linker. Ignore it. PR gdb/12528 */ long line_offset - = line_ptr - dwarf2_per_objfile->line.buffer; + = line_ptr - get_debug_line_section (cu)->buffer; complaint (&symfile_complaints, _(".debug_line address at offset 0x%lx is 0 " "[in module %s]"), - line_offset, cu->objfile->name); + line_offset, objfile->name); p_record_line = noop_record_line; } @@ -11420,8 +15444,7 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, (*p_record_line) (last_subfile, 0, addr); last_subfile = current_subfile; } - addr = check_cu_functions (address, cu); - addr = gdbarch_addr_bits_remove (gdbarch, addr); + addr = gdbarch_addr_bits_remove (gdbarch, address); (*p_record_line) (current_subfile, line, addr); } } @@ -11601,7 +15624,7 @@ dwarf_decode_lines (struct line_header *lh, const char *comp_dir, if (current_subfile->symtab == NULL) current_subfile->symtab = allocate_symtab (current_subfile->name, - cu->objfile); + objfile); fe->symtab = current_subfile->symtab; } } @@ -11658,6 +15681,23 @@ dwarf2_start_subfile (char *filename, const char *dirname, xfree (fullname); } +/* Start a symtab for DWARF. + NAME, COMP_DIR, LOW_PC are passed to start_symtab. */ + +static void +dwarf2_start_symtab (struct dwarf2_cu *cu, + const char *name, const char *comp_dir, CORE_ADDR low_pc) +{ + start_symtab (name, comp_dir, low_pc); + record_debugformat ("DWARF 2"); + record_producer (cu->producer); + + /* We assume that we're processing GCC output. */ + processing_gcc_compilation = 2; + + cu->processing_has_namespace_info = 0; +} + static void var_decode_location (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu) @@ -11685,17 +15725,24 @@ var_decode_location (struct attribute *attr, struct symbol *sym, /* Handle one degenerate form of location expression specially, to preserve GDB's previous behavior when section offsets are - specified. If this is just a DW_OP_addr then mark this symbol - as LOC_STATIC. */ + specified. If this is just a DW_OP_addr or DW_OP_GNU_addr_index + then mark this symbol as LOC_STATIC. */ if (attr_form_is_block (attr) - && DW_BLOCK (attr)->size == 1 + cu_header->addr_size - && DW_BLOCK (attr)->data[0] == DW_OP_addr) + && ((DW_BLOCK (attr)->data[0] == DW_OP_addr + && DW_BLOCK (attr)->size == 1 + cu_header->addr_size) + || (DW_BLOCK (attr)->data[0] == DW_OP_GNU_addr_index + && (DW_BLOCK (attr)->size + == 1 + leb128_size (&DW_BLOCK (attr)->data[1]))))) { unsigned int dummy; - SYMBOL_VALUE_ADDRESS (sym) = - read_address (objfile->obfd, DW_BLOCK (attr)->data + 1, cu, &dummy); + if (DW_BLOCK (attr)->data[0] == DW_OP_addr) + SYMBOL_VALUE_ADDRESS (sym) = + read_address (objfile->obfd, DW_BLOCK (attr)->data + 1, cu, &dummy); + else + SYMBOL_VALUE_ADDRESS (sym) = + read_addr_index_from_leb128 (cu, DW_BLOCK (attr)->data + 1, &dummy); SYMBOL_CLASS (sym) = LOC_STATIC; fixup_symbol_section (sym, objfile); SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets, @@ -11731,7 +15778,7 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, { struct objfile *objfile = cu->objfile; struct symbol *sym = NULL; - char *name; + const char *name; struct attribute *attr = NULL; struct attribute *attr2 = NULL; CORE_ADDR baseaddr; @@ -11763,7 +15810,7 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, if (cu->language == language_fortran && symbol_get_demangled_name (&(sym->ginfo)) == NULL) symbol_set_demangled_name (&(sym->ginfo), - (char *) dwarf2_full_name (name, die, cu), + dwarf2_full_name (name, die, cu), NULL); /* Default assumptions. @@ -11841,8 +15888,7 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, 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. */ + list_to_add = cu->list_in_scope; break; case DW_TAG_template_value_param: suppress_add = 1; @@ -11885,6 +15931,13 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, { var_decode_location (attr, sym, cu); attr2 = dwarf2_attr (die, DW_AT_external, cu); + + /* Fortran explicitly imports any global symbols to the local + scope by DW_TAG_common_block. */ + if (cu->language == language_fortran && die->parent + && die->parent->tag == DW_TAG_common_block) + attr2 = NULL; + if (SYMBOL_CLASS (sym) == LOC_STATIC && SYMBOL_VALUE_ADDRESS (sym) == 0 && !dwarf2_per_objfile->has_section_at_zero) @@ -11927,8 +15980,19 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, the minimal symbol table whenever the variable is referenced. */ attr2 = dwarf2_attr (die, DW_AT_external, cu); - if (attr2 && (DW_UNSND (attr2) != 0) - && dwarf2_attr (die, DW_AT_type, cu) != NULL) + + /* Fortran explicitly imports any global symbols to the local + scope by DW_TAG_common_block. */ + if (cu->language == language_fortran && die->parent + && die->parent->tag == DW_TAG_common_block) + { + /* SYMBOL_CLASS doesn't matter here because + read_common_block is going to reset it. */ + if (!suppress_add) + list_to_add = cu->list_in_scope; + } + else if (attr2 && (DW_UNSND (attr2) != 0) + && dwarf2_attr (die, DW_AT_type, cu) != NULL) { /* A variable with DW_AT_external is never static, but it may be block-scoped. */ @@ -12049,6 +16113,11 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, SYMBOL_CLASS (sym) = LOC_TYPEDEF; list_to_add = &global_symbols; break; + case DW_TAG_common_block: + SYMBOL_CLASS (sym) = LOC_COMMON_BLOCK; + 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 @@ -12071,7 +16140,7 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, /* For the benefit of old versions of GCC, check for anonymous namespaces based on the demangled name. */ - if (!processing_has_namespace_info + if (!cu->processing_has_namespace_info && cu->language == language_cplus) cp_scan_for_anonymous_namespaces (sym, objfile); } @@ -12097,7 +16166,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) static gdb_byte * dwarf2_const_value_data (struct attribute *attr, struct type *type, const char *name, struct obstack *obstack, - struct dwarf2_cu *cu, long *value, int bits) + struct dwarf2_cu *cu, LONGEST *value, int bits) { struct objfile *objfile = cu->objfile; enum bfd_endian byte_order = bfd_big_endian (objfile->obfd) ? @@ -12131,7 +16200,7 @@ static void dwarf2_const_value_attr (struct attribute *attr, struct type *type, const char *name, struct obstack *obstack, struct dwarf2_cu *cu, - long *value, gdb_byte **bytes, + LONGEST *value, gdb_byte **bytes, struct dwarf2_locexpr_baton **baton) { struct objfile *objfile = cu->objfile; @@ -12147,6 +16216,7 @@ dwarf2_const_value_attr (struct attribute *attr, struct type *type, switch (attr->form) { case DW_FORM_addr: + case DW_FORM_GNU_addr_index: { gdb_byte *data; @@ -12174,6 +16244,8 @@ dwarf2_const_value_attr (struct attribute *attr, struct type *type, break; case DW_FORM_string: case DW_FORM_strp: + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_strp_alt: /* DW_STRING is already allocated on the objfile obstack, point directly to it. */ *bytes = (gdb_byte *) DW_STRING (attr); @@ -12238,7 +16310,7 @@ dwarf2_const_value (struct attribute *attr, struct symbol *sym, { struct objfile *objfile = cu->objfile; struct comp_unit_head *cu_header = &cu->header; - long value; + LONGEST value; gdb_byte *bytes; struct dwarf2_locexpr_baton *baton; @@ -12355,38 +16427,52 @@ static struct type * lookup_die_type (struct die_info *die, struct attribute *attr, struct dwarf2_cu *cu) { + struct objfile *objfile = cu->objfile; struct type *this_type; /* First see if we have it cached. */ - if (is_ref_attr (attr)) + if (attr->form == DW_FORM_GNU_ref_alt) + { + struct dwarf2_per_cu_data *per_cu; + sect_offset offset = dwarf2_get_ref_die_offset (attr); + + per_cu = dwarf2_find_containing_comp_unit (offset, 1, cu->objfile); + this_type = get_die_type_at_offset (offset, per_cu); + } + else if (is_ref_attr (attr)) { - unsigned int offset = dwarf2_get_ref_die_offset (attr); + sect_offset offset = dwarf2_get_ref_die_offset (attr); this_type = get_die_type_at_offset (offset, cu->per_cu); } else if (attr->form == DW_FORM_ref_sig8) { struct signatured_type *sig_type = DW_SIGNATURED_TYPE (attr); - struct dwarf2_cu *sig_cu; - unsigned int offset; /* sig_type will be NULL if the signatured type is missing from the debug info. */ if (sig_type == NULL) error (_("Dwarf Error: Cannot find signatured DIE referenced from DIE " "at 0x%x [in module %s]"), - die->offset, cu->objfile->name); + die->offset.sect_off, objfile->name); - gdb_assert (sig_type->per_cu.debug_types_section); - offset = sig_type->per_cu.offset + sig_type->type_offset; - this_type = get_die_type_at_offset (offset, &sig_type->per_cu); + gdb_assert (sig_type->per_cu.is_debug_types); + /* If we haven't filled in type_offset_in_section yet, then we + haven't read the type in yet. */ + this_type = NULL; + if (sig_type->type_offset_in_section.sect_off != 0) + { + this_type = + get_die_type_at_offset (sig_type->type_offset_in_section, + &sig_type->per_cu); + } } else { dump_die_for_error (die); error (_("Dwarf Error: Bad type attribute %s [in module %s]"), - dwarf_attr_name (attr->name), cu->objfile->name); + dwarf_attr_name (attr->name), objfile->name); } /* If not cached we need to read it in. */ @@ -12397,9 +16483,12 @@ lookup_die_type (struct die_info *die, struct attribute *attr, struct dwarf2_cu *type_cu = cu; type_die = follow_die_ref_or_sig (die, attr, &type_cu); - /* If the type is cached, we should have found it above. */ - gdb_assert (get_die_type (type_die, type_cu) == NULL); - this_type = read_type_die_1 (type_die, type_cu); + /* If we found the type now, it's probably because the type came + from an inter-CU reference and the type's CU got expanded before + ours. */ + this_type = get_die_type (type_die, type_cu); + if (this_type == NULL) + this_type = read_type_die_1 (type_die, type_cu); } /* If we still don't have a type use an error marker. */ @@ -12410,14 +16499,14 @@ lookup_die_type (struct die_info *die, struct attribute *attr, /* read_type_die already issued a complaint. */ message = xstrprintf (_(""), - cu->objfile->name, - cu->header.offset, - die->offset); - saved = obstack_copy0 (&cu->objfile->objfile_obstack, + objfile->name, + cu->header.offset.sect_off, + die->offset.sect_off); + saved = obstack_copy0 (&objfile->objfile_obstack, message, strlen (message)); xfree (message); - this_type = init_type (TYPE_CODE_ERROR, 0, 0, saved, cu->objfile); + this_type = init_type (TYPE_CODE_ERROR, 0, 0, saved, objfile); } return this_type; @@ -12488,6 +16577,9 @@ read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu) case DW_TAG_volatile_type: this_type = read_tag_volatile_type (die, cu); break; + case DW_TAG_restrict_type: + this_type = read_tag_restrict_type (die, cu); + break; case DW_TAG_string_type: this_type = read_tag_string_type (die, cu); break; @@ -12562,7 +16654,7 @@ guess_full_die_structure_name (struct die_info *die, struct dwarf2_cu *cu) if (actual_name != NULL) { - char *die_name = dwarf2_name (die, cu); + const char *die_name = dwarf2_name (die, cu); if (die_name != NULL && strcmp (die_name, actual_name) != 0) @@ -12577,9 +16669,9 @@ guess_full_die_structure_name (struct die_info *die, struct dwarf2_cu *cu) && actual_name[actual_name_len - die_name_len - 1] == ':') name = - obsavestring (actual_name, - actual_name_len - die_name_len - 2, - &cu->objfile->objfile_obstack); + obstack_copy0 (&cu->objfile->objfile_obstack, + actual_name, + actual_name_len - die_name_len - 2); } } xfree (actual_name); @@ -12623,8 +16715,8 @@ anonymous_struct_prefix (struct die_info *die, struct dwarf2_cu *cu) if (base == NULL || base == DW_STRING (attr) || base[-1] != ':') return ""; - return obsavestring (DW_STRING (attr), &base[-1] - DW_STRING (attr), - &cu->objfile->objfile_obstack); + return obstack_copy0 (&cu->objfile->objfile_obstack, + DW_STRING (attr), &base[-1] - DW_STRING (attr)); } /* Return the name of the namespace/class that DIE is defined within, @@ -12642,7 +16734,7 @@ anonymous_struct_prefix (struct die_info *die, struct dwarf2_cu *cu) then determine_prefix on foo's die will return "N::C". */ -static char * +static const char * determine_prefix (struct die_info *die, struct dwarf2_cu *cu) { struct die_info *parent, *spec_die; @@ -12759,6 +16851,7 @@ determine_prefix (struct die_info *die, struct dwarf2_cu *cu) So it does not need a prefix. */ return ""; case DW_TAG_compile_unit: + case DW_TAG_partial_unit: /* gcc-4.5 -gdwarf-4 can drop the enclosing namespace. Cope. */ if (cu->language == language_cplus && !VEC_empty (dwarf2_section_info_def, dwarf2_per_objfile->types) @@ -12841,8 +16934,8 @@ sibling_die (struct die_info *die) /* Get name of a die, return NULL if not found. */ -static char * -dwarf2_canonicalize_name (char *name, struct dwarf2_cu *cu, +static const char * +dwarf2_canonicalize_name (const char *name, struct dwarf2_cu *cu, struct obstack *obstack) { if (name && cu->language == language_cplus) @@ -12852,8 +16945,7 @@ dwarf2_canonicalize_name (char *name, struct dwarf2_cu *cu, if (canon_name != NULL) { if (strcmp (canon_name, name) != 0) - name = obsavestring (canon_name, strlen (canon_name), - obstack); + name = obstack_copy0 (obstack, canon_name, strlen (canon_name)); xfree (canon_name); } } @@ -12863,7 +16955,7 @@ dwarf2_canonicalize_name (char *name, struct dwarf2_cu *cu, /* Get name of a die, return NULL if not found. */ -static char * +static const char * dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) { struct attribute *attr; @@ -12879,6 +16971,7 @@ dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) switch (die->tag) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: /* Compilation units have a DW_AT_name that is a filename, not a source language identifier. */ case DW_TAG_enumeration_type: @@ -12912,7 +17005,8 @@ dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) if (die->tag == DW_TAG_class_type) return dwarf2_name (die, cu); } - while (die->tag != DW_TAG_compile_unit); + while (die->tag != DW_TAG_compile_unit + && die->tag != DW_TAG_partial_unit); } break; @@ -12952,8 +17046,8 @@ dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) char *base; /* FIXME: we already did this for the partial symbol... */ - DW_STRING (attr) = obsavestring (demangled, strlen (demangled), - &cu->objfile->objfile_obstack); + DW_STRING (attr) = obstack_copy0 (&cu->objfile->objfile_obstack, + demangled, strlen (demangled)); DW_STRING_IS_CANONICAL (attr) = 1; xfree (demangled); @@ -13000,843 +17094,51 @@ dwarf2_extension (struct die_info *die, struct dwarf2_cu **ext_cu) /* Convert a DIE tag into its string name. */ -static char * +static const char * dwarf_tag_name (unsigned tag) { - switch (tag) - { - case DW_TAG_padding: - return "DW_TAG_padding"; - case DW_TAG_array_type: - return "DW_TAG_array_type"; - case DW_TAG_class_type: - return "DW_TAG_class_type"; - case DW_TAG_entry_point: - return "DW_TAG_entry_point"; - case DW_TAG_enumeration_type: - return "DW_TAG_enumeration_type"; - case DW_TAG_formal_parameter: - return "DW_TAG_formal_parameter"; - case DW_TAG_imported_declaration: - return "DW_TAG_imported_declaration"; - case DW_TAG_label: - return "DW_TAG_label"; - case DW_TAG_lexical_block: - return "DW_TAG_lexical_block"; - case DW_TAG_member: - return "DW_TAG_member"; - case DW_TAG_pointer_type: - return "DW_TAG_pointer_type"; - case DW_TAG_reference_type: - return "DW_TAG_reference_type"; - case DW_TAG_compile_unit: - return "DW_TAG_compile_unit"; - case DW_TAG_string_type: - return "DW_TAG_string_type"; - case DW_TAG_structure_type: - return "DW_TAG_structure_type"; - case DW_TAG_subroutine_type: - return "DW_TAG_subroutine_type"; - case DW_TAG_typedef: - return "DW_TAG_typedef"; - case DW_TAG_union_type: - return "DW_TAG_union_type"; - case DW_TAG_unspecified_parameters: - return "DW_TAG_unspecified_parameters"; - case DW_TAG_variant: - return "DW_TAG_variant"; - case DW_TAG_common_block: - return "DW_TAG_common_block"; - case DW_TAG_common_inclusion: - return "DW_TAG_common_inclusion"; - case DW_TAG_inheritance: - return "DW_TAG_inheritance"; - case DW_TAG_inlined_subroutine: - return "DW_TAG_inlined_subroutine"; - case DW_TAG_module: - return "DW_TAG_module"; - case DW_TAG_ptr_to_member_type: - return "DW_TAG_ptr_to_member_type"; - case DW_TAG_set_type: - return "DW_TAG_set_type"; - case DW_TAG_subrange_type: - return "DW_TAG_subrange_type"; - case DW_TAG_with_stmt: - return "DW_TAG_with_stmt"; - case DW_TAG_access_declaration: - return "DW_TAG_access_declaration"; - case DW_TAG_base_type: - return "DW_TAG_base_type"; - case DW_TAG_catch_block: - return "DW_TAG_catch_block"; - case DW_TAG_const_type: - return "DW_TAG_const_type"; - case DW_TAG_constant: - return "DW_TAG_constant"; - case DW_TAG_enumerator: - return "DW_TAG_enumerator"; - case DW_TAG_file_type: - return "DW_TAG_file_type"; - case DW_TAG_friend: - return "DW_TAG_friend"; - case DW_TAG_namelist: - return "DW_TAG_namelist"; - case DW_TAG_namelist_item: - return "DW_TAG_namelist_item"; - case DW_TAG_packed_type: - return "DW_TAG_packed_type"; - case DW_TAG_subprogram: - return "DW_TAG_subprogram"; - case DW_TAG_template_type_param: - return "DW_TAG_template_type_param"; - case DW_TAG_template_value_param: - return "DW_TAG_template_value_param"; - case DW_TAG_thrown_type: - return "DW_TAG_thrown_type"; - case DW_TAG_try_block: - return "DW_TAG_try_block"; - case DW_TAG_variant_part: - return "DW_TAG_variant_part"; - case DW_TAG_variable: - return "DW_TAG_variable"; - case DW_TAG_volatile_type: - return "DW_TAG_volatile_type"; - case DW_TAG_dwarf_procedure: - return "DW_TAG_dwarf_procedure"; - case DW_TAG_restrict_type: - return "DW_TAG_restrict_type"; - case DW_TAG_interface_type: - return "DW_TAG_interface_type"; - case DW_TAG_namespace: - return "DW_TAG_namespace"; - case DW_TAG_imported_module: - return "DW_TAG_imported_module"; - case DW_TAG_unspecified_type: - return "DW_TAG_unspecified_type"; - case DW_TAG_partial_unit: - return "DW_TAG_partial_unit"; - case DW_TAG_imported_unit: - return "DW_TAG_imported_unit"; - case DW_TAG_condition: - return "DW_TAG_condition"; - case DW_TAG_shared_type: - return "DW_TAG_shared_type"; - case DW_TAG_type_unit: - return "DW_TAG_type_unit"; - case DW_TAG_MIPS_loop: - return "DW_TAG_MIPS_loop"; - case DW_TAG_HP_array_descriptor: - return "DW_TAG_HP_array_descriptor"; - case DW_TAG_format_label: - return "DW_TAG_format_label"; - case DW_TAG_function_template: - return "DW_TAG_function_template"; - case DW_TAG_class_template: - return "DW_TAG_class_template"; - case DW_TAG_GNU_BINCL: - return "DW_TAG_GNU_BINCL"; - case DW_TAG_GNU_EINCL: - return "DW_TAG_GNU_EINCL"; - case DW_TAG_upc_shared_type: - return "DW_TAG_upc_shared_type"; - case DW_TAG_upc_strict_type: - return "DW_TAG_upc_strict_type"; - case DW_TAG_upc_relaxed_type: - return "DW_TAG_upc_relaxed_type"; - case DW_TAG_PGI_kanji_type: - return "DW_TAG_PGI_kanji_type"; - case DW_TAG_PGI_interface_block: - return "DW_TAG_PGI_interface_block"; - case DW_TAG_GNU_call_site: - return "DW_TAG_GNU_call_site"; - default: - return "DW_TAG_"; - } + const char *name = get_DW_TAG_name (tag); + + if (name == NULL) + return "DW_TAG_"; + + return name; } /* Convert a DWARF attribute code into its string name. */ -static char * +static const char * dwarf_attr_name (unsigned attr) { - switch (attr) - { - case DW_AT_sibling: - return "DW_AT_sibling"; - case DW_AT_location: - return "DW_AT_location"; - case DW_AT_name: - return "DW_AT_name"; - case DW_AT_ordering: - return "DW_AT_ordering"; - case DW_AT_subscr_data: - return "DW_AT_subscr_data"; - case DW_AT_byte_size: - return "DW_AT_byte_size"; - case DW_AT_bit_offset: - return "DW_AT_bit_offset"; - case DW_AT_bit_size: - return "DW_AT_bit_size"; - case DW_AT_element_list: - return "DW_AT_element_list"; - case DW_AT_stmt_list: - return "DW_AT_stmt_list"; - case DW_AT_low_pc: - return "DW_AT_low_pc"; - case DW_AT_high_pc: - return "DW_AT_high_pc"; - case DW_AT_language: - return "DW_AT_language"; - case DW_AT_member: - return "DW_AT_member"; - case DW_AT_discr: - return "DW_AT_discr"; - case DW_AT_discr_value: - return "DW_AT_discr_value"; - case DW_AT_visibility: - return "DW_AT_visibility"; - case DW_AT_import: - return "DW_AT_import"; - case DW_AT_string_length: - return "DW_AT_string_length"; - case DW_AT_common_reference: - return "DW_AT_common_reference"; - case DW_AT_comp_dir: - return "DW_AT_comp_dir"; - case DW_AT_const_value: - return "DW_AT_const_value"; - case DW_AT_containing_type: - return "DW_AT_containing_type"; - case DW_AT_default_value: - return "DW_AT_default_value"; - case DW_AT_inline: - return "DW_AT_inline"; - case DW_AT_is_optional: - return "DW_AT_is_optional"; - case DW_AT_lower_bound: - return "DW_AT_lower_bound"; - case DW_AT_producer: - return "DW_AT_producer"; - case DW_AT_prototyped: - return "DW_AT_prototyped"; - case DW_AT_return_addr: - return "DW_AT_return_addr"; - case DW_AT_start_scope: - return "DW_AT_start_scope"; - case DW_AT_bit_stride: - return "DW_AT_bit_stride"; - case DW_AT_upper_bound: - return "DW_AT_upper_bound"; - case DW_AT_abstract_origin: - return "DW_AT_abstract_origin"; - case DW_AT_accessibility: - return "DW_AT_accessibility"; - case DW_AT_address_class: - return "DW_AT_address_class"; - case DW_AT_artificial: - return "DW_AT_artificial"; - case DW_AT_base_types: - return "DW_AT_base_types"; - case DW_AT_calling_convention: - return "DW_AT_calling_convention"; - case DW_AT_count: - return "DW_AT_count"; - case DW_AT_data_member_location: - return "DW_AT_data_member_location"; - case DW_AT_decl_column: - return "DW_AT_decl_column"; - case DW_AT_decl_file: - return "DW_AT_decl_file"; - case DW_AT_decl_line: - return "DW_AT_decl_line"; - case DW_AT_declaration: - return "DW_AT_declaration"; - case DW_AT_discr_list: - return "DW_AT_discr_list"; - case DW_AT_encoding: - return "DW_AT_encoding"; - case DW_AT_external: - return "DW_AT_external"; - case DW_AT_frame_base: - return "DW_AT_frame_base"; - case DW_AT_friend: - return "DW_AT_friend"; - case DW_AT_identifier_case: - return "DW_AT_identifier_case"; - case DW_AT_macro_info: - return "DW_AT_macro_info"; - case DW_AT_namelist_items: - return "DW_AT_namelist_items"; - case DW_AT_priority: - return "DW_AT_priority"; - case DW_AT_segment: - return "DW_AT_segment"; - case DW_AT_specification: - return "DW_AT_specification"; - case DW_AT_static_link: - return "DW_AT_static_link"; - case DW_AT_type: - return "DW_AT_type"; - case DW_AT_use_location: - return "DW_AT_use_location"; - case DW_AT_variable_parameter: - return "DW_AT_variable_parameter"; - case DW_AT_virtuality: - return "DW_AT_virtuality"; - case DW_AT_vtable_elem_location: - return "DW_AT_vtable_elem_location"; - /* DWARF 3 values. */ - case DW_AT_allocated: - return "DW_AT_allocated"; - case DW_AT_associated: - return "DW_AT_associated"; - case DW_AT_data_location: - return "DW_AT_data_location"; - case DW_AT_byte_stride: - return "DW_AT_byte_stride"; - case DW_AT_entry_pc: - return "DW_AT_entry_pc"; - case DW_AT_use_UTF8: - return "DW_AT_use_UTF8"; - case DW_AT_extension: - return "DW_AT_extension"; - case DW_AT_ranges: - return "DW_AT_ranges"; - case DW_AT_trampoline: - return "DW_AT_trampoline"; - case DW_AT_call_column: - return "DW_AT_call_column"; - case DW_AT_call_file: - return "DW_AT_call_file"; - case DW_AT_call_line: - return "DW_AT_call_line"; - case DW_AT_description: - return "DW_AT_description"; - case DW_AT_binary_scale: - return "DW_AT_binary_scale"; - case DW_AT_decimal_scale: - return "DW_AT_decimal_scale"; - case DW_AT_small: - return "DW_AT_small"; - case DW_AT_decimal_sign: - return "DW_AT_decimal_sign"; - case DW_AT_digit_count: - return "DW_AT_digit_count"; - case DW_AT_picture_string: - return "DW_AT_picture_string"; - case DW_AT_mutable: - return "DW_AT_mutable"; - case DW_AT_threads_scaled: - return "DW_AT_threads_scaled"; - case DW_AT_explicit: - return "DW_AT_explicit"; - case DW_AT_object_pointer: - return "DW_AT_object_pointer"; - case DW_AT_endianity: - return "DW_AT_endianity"; - case DW_AT_elemental: - return "DW_AT_elemental"; - case DW_AT_pure: - return "DW_AT_pure"; - case DW_AT_recursive: - return "DW_AT_recursive"; - /* DWARF 4 values. */ - case DW_AT_signature: - return "DW_AT_signature"; - case DW_AT_linkage_name: - return "DW_AT_linkage_name"; - /* SGI/MIPS extensions. */ + const char *name; + #ifdef MIPS /* collides with DW_AT_HP_block_index */ - case DW_AT_MIPS_fde: - return "DW_AT_MIPS_fde"; -#endif - case DW_AT_MIPS_loop_begin: - return "DW_AT_MIPS_loop_begin"; - case DW_AT_MIPS_tail_loop_begin: - return "DW_AT_MIPS_tail_loop_begin"; - case DW_AT_MIPS_epilog_begin: - return "DW_AT_MIPS_epilog_begin"; - case DW_AT_MIPS_loop_unroll_factor: - return "DW_AT_MIPS_loop_unroll_factor"; - case DW_AT_MIPS_software_pipeline_depth: - return "DW_AT_MIPS_software_pipeline_depth"; - case DW_AT_MIPS_linkage_name: - return "DW_AT_MIPS_linkage_name"; - case DW_AT_MIPS_stride: - return "DW_AT_MIPS_stride"; - case DW_AT_MIPS_abstract_name: - return "DW_AT_MIPS_abstract_name"; - case DW_AT_MIPS_clone_origin: - return "DW_AT_MIPS_clone_origin"; - case DW_AT_MIPS_has_inlines: - return "DW_AT_MIPS_has_inlines"; - /* HP extensions. */ -#ifndef MIPS /* collides with DW_AT_MIPS_fde */ - case DW_AT_HP_block_index: - return "DW_AT_HP_block_index"; + if (attr == DW_AT_MIPS_fde) + return "DW_AT_MIPS_fde"; +#else + if (attr == DW_AT_HP_block_index) + return "DW_AT_HP_block_index"; #endif - case DW_AT_HP_unmodifiable: - return "DW_AT_HP_unmodifiable"; - case DW_AT_HP_actuals_stmt_list: - return "DW_AT_HP_actuals_stmt_list"; - case DW_AT_HP_proc_per_section: - return "DW_AT_HP_proc_per_section"; - case DW_AT_HP_raw_data_ptr: - return "DW_AT_HP_raw_data_ptr"; - case DW_AT_HP_pass_by_reference: - return "DW_AT_HP_pass_by_reference"; - case DW_AT_HP_opt_level: - return "DW_AT_HP_opt_level"; - case DW_AT_HP_prof_version_id: - return "DW_AT_HP_prof_version_id"; - case DW_AT_HP_opt_flags: - return "DW_AT_HP_opt_flags"; - case DW_AT_HP_cold_region_low_pc: - return "DW_AT_HP_cold_region_low_pc"; - case DW_AT_HP_cold_region_high_pc: - return "DW_AT_HP_cold_region_high_pc"; - case DW_AT_HP_all_variables_modifiable: - return "DW_AT_HP_all_variables_modifiable"; - case DW_AT_HP_linkage_name: - return "DW_AT_HP_linkage_name"; - case DW_AT_HP_prof_flags: - return "DW_AT_HP_prof_flags"; - /* GNU extensions. */ - case DW_AT_sf_names: - return "DW_AT_sf_names"; - case DW_AT_src_info: - return "DW_AT_src_info"; - case DW_AT_mac_info: - return "DW_AT_mac_info"; - case DW_AT_src_coords: - return "DW_AT_src_coords"; - case DW_AT_body_begin: - return "DW_AT_body_begin"; - case DW_AT_body_end: - return "DW_AT_body_end"; - case DW_AT_GNU_vector: - return "DW_AT_GNU_vector"; - case DW_AT_GNU_odr_signature: - return "DW_AT_GNU_odr_signature"; - /* VMS extensions. */ - case DW_AT_VMS_rtnbeg_pd_address: - return "DW_AT_VMS_rtnbeg_pd_address"; - /* UPC extension. */ - case DW_AT_upc_threads_scaled: - return "DW_AT_upc_threads_scaled"; - /* PGI (STMicroelectronics) extensions. */ - case DW_AT_PGI_lbase: - return "DW_AT_PGI_lbase"; - case DW_AT_PGI_soffset: - return "DW_AT_PGI_soffset"; - case DW_AT_PGI_lstride: - return "DW_AT_PGI_lstride"; - default: - return "DW_AT_"; - } + + name = get_DW_AT_name (attr); + + if (name == NULL) + return "DW_AT_"; + + return name; } /* Convert a DWARF value form code into its string name. */ -static char * +static const char * dwarf_form_name (unsigned form) { - switch (form) - { - case DW_FORM_addr: - return "DW_FORM_addr"; - case DW_FORM_block2: - return "DW_FORM_block2"; - case DW_FORM_block4: - return "DW_FORM_block4"; - case DW_FORM_data2: - return "DW_FORM_data2"; - case DW_FORM_data4: - return "DW_FORM_data4"; - case DW_FORM_data8: - return "DW_FORM_data8"; - case DW_FORM_string: - return "DW_FORM_string"; - case DW_FORM_block: - return "DW_FORM_block"; - case DW_FORM_block1: - return "DW_FORM_block1"; - case DW_FORM_data1: - return "DW_FORM_data1"; - case DW_FORM_flag: - return "DW_FORM_flag"; - case DW_FORM_sdata: - return "DW_FORM_sdata"; - case DW_FORM_strp: - return "DW_FORM_strp"; - case DW_FORM_udata: - return "DW_FORM_udata"; - case DW_FORM_ref_addr: - return "DW_FORM_ref_addr"; - case DW_FORM_ref1: - return "DW_FORM_ref1"; - case DW_FORM_ref2: - return "DW_FORM_ref2"; - case DW_FORM_ref4: - return "DW_FORM_ref4"; - case DW_FORM_ref8: - return "DW_FORM_ref8"; - case DW_FORM_ref_udata: - return "DW_FORM_ref_udata"; - case DW_FORM_indirect: - return "DW_FORM_indirect"; - case DW_FORM_sec_offset: - return "DW_FORM_sec_offset"; - case DW_FORM_exprloc: - return "DW_FORM_exprloc"; - case DW_FORM_flag_present: - return "DW_FORM_flag_present"; - case DW_FORM_ref_sig8: - return "DW_FORM_ref_sig8"; - default: - return "DW_FORM_"; - } -} - -/* Convert a DWARF stack opcode into its string name. */ - -const char * -dwarf_stack_op_name (unsigned op) -{ - switch (op) - { - case DW_OP_addr: - return "DW_OP_addr"; - case DW_OP_deref: - return "DW_OP_deref"; - case DW_OP_const1u: - return "DW_OP_const1u"; - case DW_OP_const1s: - return "DW_OP_const1s"; - case DW_OP_const2u: - return "DW_OP_const2u"; - case DW_OP_const2s: - return "DW_OP_const2s"; - case DW_OP_const4u: - return "DW_OP_const4u"; - case DW_OP_const4s: - return "DW_OP_const4s"; - case DW_OP_const8u: - return "DW_OP_const8u"; - case DW_OP_const8s: - return "DW_OP_const8s"; - case DW_OP_constu: - return "DW_OP_constu"; - case DW_OP_consts: - return "DW_OP_consts"; - case DW_OP_dup: - return "DW_OP_dup"; - case DW_OP_drop: - return "DW_OP_drop"; - case DW_OP_over: - return "DW_OP_over"; - case DW_OP_pick: - return "DW_OP_pick"; - case DW_OP_swap: - return "DW_OP_swap"; - case DW_OP_rot: - return "DW_OP_rot"; - case DW_OP_xderef: - return "DW_OP_xderef"; - case DW_OP_abs: - return "DW_OP_abs"; - case DW_OP_and: - return "DW_OP_and"; - case DW_OP_div: - return "DW_OP_div"; - case DW_OP_minus: - return "DW_OP_minus"; - case DW_OP_mod: - return "DW_OP_mod"; - case DW_OP_mul: - return "DW_OP_mul"; - case DW_OP_neg: - return "DW_OP_neg"; - case DW_OP_not: - return "DW_OP_not"; - case DW_OP_or: - return "DW_OP_or"; - case DW_OP_plus: - return "DW_OP_plus"; - case DW_OP_plus_uconst: - return "DW_OP_plus_uconst"; - case DW_OP_shl: - return "DW_OP_shl"; - case DW_OP_shr: - return "DW_OP_shr"; - case DW_OP_shra: - return "DW_OP_shra"; - case DW_OP_xor: - return "DW_OP_xor"; - case DW_OP_bra: - return "DW_OP_bra"; - case DW_OP_eq: - return "DW_OP_eq"; - case DW_OP_ge: - return "DW_OP_ge"; - case DW_OP_gt: - return "DW_OP_gt"; - case DW_OP_le: - return "DW_OP_le"; - case DW_OP_lt: - return "DW_OP_lt"; - case DW_OP_ne: - return "DW_OP_ne"; - case DW_OP_skip: - return "DW_OP_skip"; - case DW_OP_lit0: - return "DW_OP_lit0"; - case DW_OP_lit1: - return "DW_OP_lit1"; - case DW_OP_lit2: - return "DW_OP_lit2"; - case DW_OP_lit3: - return "DW_OP_lit3"; - case DW_OP_lit4: - return "DW_OP_lit4"; - case DW_OP_lit5: - return "DW_OP_lit5"; - case DW_OP_lit6: - return "DW_OP_lit6"; - case DW_OP_lit7: - return "DW_OP_lit7"; - case DW_OP_lit8: - return "DW_OP_lit8"; - case DW_OP_lit9: - return "DW_OP_lit9"; - case DW_OP_lit10: - return "DW_OP_lit10"; - case DW_OP_lit11: - return "DW_OP_lit11"; - case DW_OP_lit12: - return "DW_OP_lit12"; - case DW_OP_lit13: - return "DW_OP_lit13"; - case DW_OP_lit14: - return "DW_OP_lit14"; - case DW_OP_lit15: - return "DW_OP_lit15"; - case DW_OP_lit16: - return "DW_OP_lit16"; - case DW_OP_lit17: - return "DW_OP_lit17"; - case DW_OP_lit18: - return "DW_OP_lit18"; - case DW_OP_lit19: - return "DW_OP_lit19"; - case DW_OP_lit20: - return "DW_OP_lit20"; - case DW_OP_lit21: - return "DW_OP_lit21"; - case DW_OP_lit22: - return "DW_OP_lit22"; - case DW_OP_lit23: - return "DW_OP_lit23"; - case DW_OP_lit24: - return "DW_OP_lit24"; - case DW_OP_lit25: - return "DW_OP_lit25"; - case DW_OP_lit26: - return "DW_OP_lit26"; - case DW_OP_lit27: - return "DW_OP_lit27"; - case DW_OP_lit28: - return "DW_OP_lit28"; - case DW_OP_lit29: - return "DW_OP_lit29"; - case DW_OP_lit30: - return "DW_OP_lit30"; - case DW_OP_lit31: - return "DW_OP_lit31"; - case DW_OP_reg0: - return "DW_OP_reg0"; - case DW_OP_reg1: - return "DW_OP_reg1"; - case DW_OP_reg2: - return "DW_OP_reg2"; - case DW_OP_reg3: - return "DW_OP_reg3"; - case DW_OP_reg4: - return "DW_OP_reg4"; - case DW_OP_reg5: - return "DW_OP_reg5"; - case DW_OP_reg6: - return "DW_OP_reg6"; - case DW_OP_reg7: - return "DW_OP_reg7"; - case DW_OP_reg8: - return "DW_OP_reg8"; - case DW_OP_reg9: - return "DW_OP_reg9"; - case DW_OP_reg10: - return "DW_OP_reg10"; - case DW_OP_reg11: - return "DW_OP_reg11"; - case DW_OP_reg12: - return "DW_OP_reg12"; - case DW_OP_reg13: - return "DW_OP_reg13"; - case DW_OP_reg14: - return "DW_OP_reg14"; - case DW_OP_reg15: - return "DW_OP_reg15"; - case DW_OP_reg16: - return "DW_OP_reg16"; - case DW_OP_reg17: - return "DW_OP_reg17"; - case DW_OP_reg18: - return "DW_OP_reg18"; - case DW_OP_reg19: - return "DW_OP_reg19"; - case DW_OP_reg20: - return "DW_OP_reg20"; - case DW_OP_reg21: - return "DW_OP_reg21"; - case DW_OP_reg22: - return "DW_OP_reg22"; - case DW_OP_reg23: - return "DW_OP_reg23"; - case DW_OP_reg24: - return "DW_OP_reg24"; - case DW_OP_reg25: - return "DW_OP_reg25"; - case DW_OP_reg26: - return "DW_OP_reg26"; - case DW_OP_reg27: - return "DW_OP_reg27"; - case DW_OP_reg28: - return "DW_OP_reg28"; - case DW_OP_reg29: - return "DW_OP_reg29"; - case DW_OP_reg30: - return "DW_OP_reg30"; - case DW_OP_reg31: - return "DW_OP_reg31"; - case DW_OP_breg0: - return "DW_OP_breg0"; - case DW_OP_breg1: - return "DW_OP_breg1"; - case DW_OP_breg2: - return "DW_OP_breg2"; - case DW_OP_breg3: - return "DW_OP_breg3"; - case DW_OP_breg4: - return "DW_OP_breg4"; - case DW_OP_breg5: - return "DW_OP_breg5"; - case DW_OP_breg6: - return "DW_OP_breg6"; - case DW_OP_breg7: - return "DW_OP_breg7"; - case DW_OP_breg8: - return "DW_OP_breg8"; - case DW_OP_breg9: - return "DW_OP_breg9"; - case DW_OP_breg10: - return "DW_OP_breg10"; - case DW_OP_breg11: - return "DW_OP_breg11"; - case DW_OP_breg12: - return "DW_OP_breg12"; - case DW_OP_breg13: - return "DW_OP_breg13"; - case DW_OP_breg14: - return "DW_OP_breg14"; - case DW_OP_breg15: - return "DW_OP_breg15"; - case DW_OP_breg16: - return "DW_OP_breg16"; - case DW_OP_breg17: - return "DW_OP_breg17"; - case DW_OP_breg18: - return "DW_OP_breg18"; - case DW_OP_breg19: - return "DW_OP_breg19"; - case DW_OP_breg20: - return "DW_OP_breg20"; - case DW_OP_breg21: - return "DW_OP_breg21"; - case DW_OP_breg22: - return "DW_OP_breg22"; - case DW_OP_breg23: - return "DW_OP_breg23"; - case DW_OP_breg24: - return "DW_OP_breg24"; - case DW_OP_breg25: - return "DW_OP_breg25"; - case DW_OP_breg26: - return "DW_OP_breg26"; - case DW_OP_breg27: - return "DW_OP_breg27"; - case DW_OP_breg28: - return "DW_OP_breg28"; - case DW_OP_breg29: - return "DW_OP_breg29"; - case DW_OP_breg30: - return "DW_OP_breg30"; - case DW_OP_breg31: - return "DW_OP_breg31"; - case DW_OP_regx: - return "DW_OP_regx"; - case DW_OP_fbreg: - return "DW_OP_fbreg"; - case DW_OP_bregx: - return "DW_OP_bregx"; - case DW_OP_piece: - return "DW_OP_piece"; - case DW_OP_deref_size: - return "DW_OP_deref_size"; - case DW_OP_xderef_size: - return "DW_OP_xderef_size"; - case DW_OP_nop: - return "DW_OP_nop"; - /* DWARF 3 extensions. */ - case DW_OP_push_object_address: - return "DW_OP_push_object_address"; - case DW_OP_call2: - return "DW_OP_call2"; - case DW_OP_call4: - return "DW_OP_call4"; - case DW_OP_call_ref: - return "DW_OP_call_ref"; - case DW_OP_form_tls_address: - return "DW_OP_form_tls_address"; - case DW_OP_call_frame_cfa: - return "DW_OP_call_frame_cfa"; - case DW_OP_bit_piece: - return "DW_OP_bit_piece"; - /* DWARF 4 extensions. */ - case DW_OP_implicit_value: - return "DW_OP_implicit_value"; - case DW_OP_stack_value: - return "DW_OP_stack_value"; - /* GNU extensions. */ - case DW_OP_GNU_push_tls_address: - return "DW_OP_GNU_push_tls_address"; - case DW_OP_GNU_uninit: - return "DW_OP_GNU_uninit"; - case DW_OP_GNU_implicit_pointer: - return "DW_OP_GNU_implicit_pointer"; - case DW_OP_GNU_entry_value: - return "DW_OP_GNU_entry_value"; - case DW_OP_GNU_const_type: - return "DW_OP_GNU_const_type"; - case DW_OP_GNU_regval_type: - return "DW_OP_GNU_regval_type"; - case DW_OP_GNU_deref_type: - return "DW_OP_GNU_deref_type"; - case DW_OP_GNU_convert: - return "DW_OP_GNU_convert"; - case DW_OP_GNU_reinterpret: - return "DW_OP_GNU_reinterpret"; - default: - return NULL; - } + const char *name = get_DW_FORM_name (form); + + if (name == NULL) + return "DW_FORM_"; + + return name; } static char * @@ -13850,143 +17152,16 @@ dwarf_bool_name (unsigned mybool) /* Convert a DWARF type code into its string name. */ -static char * +static const char * dwarf_type_encoding_name (unsigned enc) { - switch (enc) - { - case DW_ATE_void: - return "DW_ATE_void"; - case DW_ATE_address: - return "DW_ATE_address"; - case DW_ATE_boolean: - return "DW_ATE_boolean"; - case DW_ATE_complex_float: - return "DW_ATE_complex_float"; - case DW_ATE_float: - return "DW_ATE_float"; - case DW_ATE_signed: - return "DW_ATE_signed"; - case DW_ATE_signed_char: - return "DW_ATE_signed_char"; - case DW_ATE_unsigned: - return "DW_ATE_unsigned"; - case DW_ATE_unsigned_char: - return "DW_ATE_unsigned_char"; - /* DWARF 3. */ - case DW_ATE_imaginary_float: - return "DW_ATE_imaginary_float"; - case DW_ATE_packed_decimal: - return "DW_ATE_packed_decimal"; - case DW_ATE_numeric_string: - return "DW_ATE_numeric_string"; - case DW_ATE_edited: - return "DW_ATE_edited"; - case DW_ATE_signed_fixed: - return "DW_ATE_signed_fixed"; - case DW_ATE_unsigned_fixed: - return "DW_ATE_unsigned_fixed"; - case DW_ATE_decimal_float: - return "DW_ATE_decimal_float"; - /* DWARF 4. */ - case DW_ATE_UTF: - return "DW_ATE_UTF"; - /* HP extensions. */ - case DW_ATE_HP_float80: - return "DW_ATE_HP_float80"; - case DW_ATE_HP_complex_float80: - return "DW_ATE_HP_complex_float80"; - case DW_ATE_HP_float128: - return "DW_ATE_HP_float128"; - case DW_ATE_HP_complex_float128: - return "DW_ATE_HP_complex_float128"; - case DW_ATE_HP_floathpintel: - return "DW_ATE_HP_floathpintel"; - case DW_ATE_HP_imaginary_float80: - return "DW_ATE_HP_imaginary_float80"; - case DW_ATE_HP_imaginary_float128: - return "DW_ATE_HP_imaginary_float128"; - default: - return "DW_ATE_"; - } -} + const char *name = get_DW_ATE_name (enc); -/* Convert a DWARF call frame info operation to its string name. */ + if (name == NULL) + return "DW_ATE_"; -#if 0 -static char * -dwarf_cfi_name (unsigned cfi_opc) -{ - switch (cfi_opc) - { - case DW_CFA_advance_loc: - return "DW_CFA_advance_loc"; - case DW_CFA_offset: - return "DW_CFA_offset"; - case DW_CFA_restore: - return "DW_CFA_restore"; - case DW_CFA_nop: - return "DW_CFA_nop"; - case DW_CFA_set_loc: - return "DW_CFA_set_loc"; - case DW_CFA_advance_loc1: - return "DW_CFA_advance_loc1"; - case DW_CFA_advance_loc2: - return "DW_CFA_advance_loc2"; - case DW_CFA_advance_loc4: - return "DW_CFA_advance_loc4"; - case DW_CFA_offset_extended: - return "DW_CFA_offset_extended"; - case DW_CFA_restore_extended: - return "DW_CFA_restore_extended"; - case DW_CFA_undefined: - return "DW_CFA_undefined"; - case DW_CFA_same_value: - return "DW_CFA_same_value"; - case DW_CFA_register: - return "DW_CFA_register"; - case DW_CFA_remember_state: - return "DW_CFA_remember_state"; - case DW_CFA_restore_state: - return "DW_CFA_restore_state"; - case DW_CFA_def_cfa: - return "DW_CFA_def_cfa"; - case DW_CFA_def_cfa_register: - return "DW_CFA_def_cfa_register"; - case DW_CFA_def_cfa_offset: - return "DW_CFA_def_cfa_offset"; - /* DWARF 3. */ - case DW_CFA_def_cfa_expression: - return "DW_CFA_def_cfa_expression"; - case DW_CFA_expression: - return "DW_CFA_expression"; - case DW_CFA_offset_extended_sf: - return "DW_CFA_offset_extended_sf"; - case DW_CFA_def_cfa_sf: - return "DW_CFA_def_cfa_sf"; - case DW_CFA_def_cfa_offset_sf: - return "DW_CFA_def_cfa_offset_sf"; - case DW_CFA_val_offset: - return "DW_CFA_val_offset"; - case DW_CFA_val_offset_sf: - return "DW_CFA_val_offset_sf"; - case DW_CFA_val_expression: - return "DW_CFA_val_expression"; - /* SGI/MIPS specific. */ - case DW_CFA_MIPS_advance_loc8: - return "DW_CFA_MIPS_advance_loc8"; - /* GNU extensions. */ - case DW_CFA_GNU_window_save: - return "DW_CFA_GNU_window_save"; - case DW_CFA_GNU_args_size: - return "DW_CFA_GNU_args_size"; - case DW_CFA_GNU_negative_offset_extended: - return "DW_CFA_GNU_negative_offset_extended"; - default: - return "DW_CFA_"; - } + return name; } -#endif static void dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) @@ -13995,13 +17170,13 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) print_spaces (indent, f); fprintf_unfiltered (f, "Die: %s (abbrev %d, offset 0x%x)\n", - dwarf_tag_name (die->tag), die->abbrev, die->offset); + dwarf_tag_name (die->tag), die->abbrev, die->offset.sect_off); if (die->parent != NULL) { print_spaces (indent, f); fprintf_unfiltered (f, " parent at offset: 0x%x\n", - die->parent->offset); + die->parent->offset.sect_off); } print_spaces (indent, f); @@ -14020,8 +17195,8 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) switch (die->attrs[i].form) { - case DW_FORM_ref_addr: case DW_FORM_addr: + case DW_FORM_GNU_addr_index: fprintf_unfiltered (f, "address: "); fputs_filtered (hex_string (DW_ADDR (&die->attrs[i])), f); break; @@ -14029,18 +17204,28 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) case DW_FORM_block4: case DW_FORM_block: case DW_FORM_block1: - fprintf_unfiltered (f, "block: size %d", - DW_BLOCK (&die->attrs[i])->size); + fprintf_unfiltered (f, "block: size %s", + pulongest (DW_BLOCK (&die->attrs[i])->size)); break; case DW_FORM_exprloc: - fprintf_unfiltered (f, "expression: size %u", - DW_BLOCK (&die->attrs[i])->size); + fprintf_unfiltered (f, "expression: size %s", + pulongest (DW_BLOCK (&die->attrs[i])->size)); + break; + case DW_FORM_ref_addr: + fprintf_unfiltered (f, "ref address: "); + fputs_filtered (hex_string (DW_UNSND (&die->attrs[i])), f); + break; + case DW_FORM_GNU_ref_alt: + fprintf_unfiltered (f, "alt ref address: "); + fputs_filtered (hex_string (DW_UNSND (&die->attrs[i])), f); break; case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: fprintf_unfiltered (f, "constant ref: 0x%lx (adjusted)", - (long) (DW_ADDR (&die->attrs[i]))); + (long) (DW_UNSND (&die->attrs[i]))); break; case DW_FORM_data1: case DW_FORM_data2: @@ -14058,12 +17243,14 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) case DW_FORM_ref_sig8: if (DW_SIGNATURED_TYPE (&die->attrs[i]) != NULL) fprintf_unfiltered (f, "signatured type, offset: 0x%x", - DW_SIGNATURED_TYPE (&die->attrs[i])->per_cu.offset); + DW_SIGNATURED_TYPE (&die->attrs[i])->per_cu.offset.sect_off); else fprintf_unfiltered (f, "signatured type, offset: unknown"); break; case DW_FORM_string: case DW_FORM_strp: + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_strp_alt: fprintf_unfiltered (f, "string: \"%s\" (%s canonicalized)", DW_STRING (&die->attrs[i]) ? DW_STRING (&die->attrs[i]) : "", @@ -14147,11 +17334,15 @@ store_in_ref_table (struct die_info *die, struct dwarf2_cu *cu) { void **slot; - slot = htab_find_slot_with_hash (cu->die_hash, die, die->offset, INSERT); + slot = htab_find_slot_with_hash (cu->die_hash, die, die->offset.sect_off, + INSERT); *slot = die; } +/* DW_ADDR is always stored already as sect_offset; despite for the forms + besides DW_FORM_ref_addr it is stored as cu_offset in the DWARF file. */ + static int is_ref_attr (struct attribute *attr) { @@ -14163,22 +17354,29 @@ is_ref_attr (struct attribute *attr) case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: + case DW_FORM_GNU_ref_alt: return 1; default: return 0; } } -static unsigned int +/* Return DIE offset of ATTR. Return 0 with complaint if ATTR is not of the + required kind. */ + +static sect_offset dwarf2_get_ref_die_offset (struct attribute *attr) { + sect_offset retval = { DW_UNSND (attr) }; + if (is_ref_attr (attr)) - return DW_ADDR (attr); + return retval; + retval.sect_off = 0; complaint (&symfile_complaints, _("unsupported die ref attribute form: '%s'"), dwarf_form_name (attr->form)); - return 0; + return retval; } /* Return the constant value held by ATTR. Return DEFAULT_VALUE if @@ -14196,53 +17394,12 @@ dwarf2_get_attr_constant_value (struct attribute *attr, int default_value) || 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; - } -} - -/* THIS_CU has a reference to PER_CU. If necessary, load the new compilation - unit and add it to our queue. - The result is non-zero if PER_CU was queued, otherwise the result is zero - meaning either PER_CU is already queued or it is already loaded. */ - -static int -maybe_queue_comp_unit (struct dwarf2_cu *this_cu, - struct dwarf2_per_cu_data *per_cu) -{ - /* We may arrive here during partial symbol reading, if we need full - DIEs to process an unusual case (e.g. template arguments). Do - not queue PER_CU, just tell our caller to load its DIEs. */ - if (dwarf2_per_objfile->reading_partial_symbols) - { - if (per_cu->cu == NULL || per_cu->cu->dies == NULL) - return 1; - return 0; - } - - /* Mark the dependence relation so that we don't flush PER_CU - too early. */ - dwarf2_add_dependence (this_cu, per_cu); - - /* If it's already on the queue, we have nothing to do. */ - if (per_cu->queued) - return 0; - - /* If the compilation unit is already loaded, just mark it as - used. */ - if (per_cu->cu != NULL) - { - per_cu->cu->last_used = 0; - return 0; + { + complaint (&symfile_complaints, + _("Attribute value is not a constant (%s)"), + dwarf_form_name (attr->form)); + return default_value; } - - /* Add it to the queue. */ - queue_comp_unit (per_cu, this_cu->objfile); - - return 1; } /* Follow reference or signature attribute ATTR of SRC_DIE. @@ -14275,7 +17432,8 @@ follow_die_ref_or_sig (struct die_info *src_die, struct attribute *attr, Returns NULL if OFFSET is invalid. */ static struct die_info * -follow_die_offset (unsigned int offset, struct dwarf2_cu **ref_cu) +follow_die_offset (sect_offset offset, int offset_in_dwz, + struct dwarf2_cu **ref_cu) { struct die_info temp_die; struct dwarf2_cu *target_cu, *cu = *ref_cu; @@ -14284,7 +17442,7 @@ follow_die_offset (unsigned int offset, struct dwarf2_cu **ref_cu) target_cu = cu; - if (cu->per_cu->debug_types_section) + if (cu->per_cu->is_debug_types) { /* .debug_types CUs cannot reference anything outside their CU. If they need to, they have to reference a signatured type via @@ -14292,15 +17450,17 @@ follow_die_offset (unsigned int offset, struct dwarf2_cu **ref_cu) if (! offset_in_cu_p (&cu->header, offset)) return NULL; } - else if (! offset_in_cu_p (&cu->header, offset)) + else if (offset_in_dwz != cu->per_cu->is_dwz + || ! offset_in_cu_p (&cu->header, offset)) { struct dwarf2_per_cu_data *per_cu; - per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile); + per_cu = dwarf2_find_containing_comp_unit (offset, offset_in_dwz, + cu->objfile); /* If necessary, add it to the queue and load its DIEs. */ - if (maybe_queue_comp_unit (cu, per_cu)) - load_full_comp_unit (per_cu, cu->objfile); + if (maybe_queue_comp_unit (cu, per_cu, cu->language)) + load_full_comp_unit (per_cu, cu->language); target_cu = per_cu->cu; } @@ -14308,12 +17468,12 @@ follow_die_offset (unsigned int offset, struct dwarf2_cu **ref_cu) { /* We're loading full DIEs during partial symbol reading. */ gdb_assert (dwarf2_per_objfile->reading_partial_symbols); - load_full_comp_unit (cu->per_cu, cu->objfile); + load_full_comp_unit (cu->per_cu, language_minimal); } *ref_cu = target_cu; temp_die.offset = offset; - return htab_find_with_hash (target_cu->die_hash, &temp_die, offset); + return htab_find_with_hash (target_cu->die_hash, &temp_die, offset.sect_off); } /* Follow reference attribute ATTR of SRC_DIE. @@ -14324,15 +17484,18 @@ static struct die_info * follow_die_ref (struct die_info *src_die, struct attribute *attr, struct dwarf2_cu **ref_cu) { - unsigned int offset = dwarf2_get_ref_die_offset (attr); + sect_offset offset = dwarf2_get_ref_die_offset (attr); struct dwarf2_cu *cu = *ref_cu; struct die_info *die; - die = follow_die_offset (offset, ref_cu); + die = follow_die_offset (offset, + (attr->form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz), + ref_cu); if (!die) error (_("Dwarf Error: Cannot find DIE at 0x%x referenced from DIE " "at 0x%x [in module %s]"), - offset, src_die->offset, cu->objfile->name); + offset.sect_off, src_die->offset.sect_off, cu->objfile->name); return die; } @@ -14342,10 +17505,10 @@ follow_die_ref (struct die_info *src_die, struct attribute *attr, dwarf2_locexpr_baton->data has lifetime of PER_CU->OBJFILE. */ struct dwarf2_locexpr_baton -dwarf2_fetch_die_location_block (unsigned int offset, - struct dwarf2_per_cu_data *per_cu, - CORE_ADDR (*get_frame_pc) (void *baton), - void *baton) +dwarf2_fetch_die_loc_sect_off (sect_offset offset, + struct dwarf2_per_cu_data *per_cu, + CORE_ADDR (*get_frame_pc) (void *baton), + void *baton) { struct dwarf2_cu *cu; struct die_info *die; @@ -14358,10 +17521,10 @@ dwarf2_fetch_die_location_block (unsigned int offset, load_cu (per_cu); cu = per_cu->cu; - die = follow_die_offset (offset, &cu); + die = follow_die_offset (offset, per_cu->is_dwz, &cu); if (!die) error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"), - offset, per_cu->cu->objfile->name); + offset.sect_off, per_cu->objfile->name); attr = dwarf2_attr (die, DW_AT_location, cu); if (!attr) @@ -14389,7 +17552,7 @@ dwarf2_fetch_die_location_block (unsigned int offset, if (!attr_form_is_block (attr)) error (_("Dwarf Error: DIE at 0x%x referenced in module %s " "is neither DW_FORM_block* nor DW_FORM_exprloc"), - offset, per_cu->cu->objfile->name); + offset.sect_off, per_cu->objfile->name); retval.data = DW_BLOCK (attr)->data; retval.size = DW_BLOCK (attr)->size; @@ -14401,15 +17564,33 @@ dwarf2_fetch_die_location_block (unsigned int offset, return retval; } +/* Like dwarf2_fetch_die_loc_sect_off, but take a CU + offset. */ + +struct dwarf2_locexpr_baton +dwarf2_fetch_die_loc_cu_off (cu_offset offset_in_cu, + struct dwarf2_per_cu_data *per_cu, + CORE_ADDR (*get_frame_pc) (void *baton), + void *baton) +{ + sect_offset offset = { per_cu->offset.sect_off + offset_in_cu.cu_off }; + + return dwarf2_fetch_die_loc_sect_off (offset, per_cu, get_frame_pc, baton); +} + /* Return the type of the DIE at DIE_OFFSET in the CU named by PER_CU. */ struct type * -dwarf2_get_die_type (unsigned int die_offset, +dwarf2_get_die_type (cu_offset die_offset, struct dwarf2_per_cu_data *per_cu) { + sect_offset die_offset_sect; + dw2_setup (per_cu->objfile); - return get_die_type_at_offset (die_offset, per_cu); + + die_offset_sect.sect_off = per_cu->offset.sect_off + die_offset.cu_off; + return get_die_type_at_offset (die_offset_sect, per_cu); } /* Follow the signature attribute ATTR in SRC_DIE. @@ -14431,27 +17612,39 @@ follow_die_sig (struct die_info *src_die, struct attribute *attr, if (sig_type == NULL) error (_("Dwarf Error: Cannot find signatured DIE referenced from DIE " "at 0x%x [in module %s]"), - src_die->offset, objfile->name); + src_die->offset.sect_off, objfile->name); /* If necessary, add it to the queue and load its DIEs. */ - if (maybe_queue_comp_unit (*ref_cu, &sig_type->per_cu)) - read_signatured_type (objfile, sig_type); + if (maybe_queue_comp_unit (*ref_cu, &sig_type->per_cu, language_minimal)) + read_signatured_type (sig_type); gdb_assert (sig_type->per_cu.cu != NULL); sig_cu = sig_type->per_cu.cu; - temp_die.offset = sig_cu->header.offset + sig_type->type_offset; - die = htab_find_with_hash (sig_cu->die_hash, &temp_die, temp_die.offset); + gdb_assert (sig_type->type_offset_in_section.sect_off != 0); + temp_die.offset = sig_type->type_offset_in_section; + die = htab_find_with_hash (sig_cu->die_hash, &temp_die, + temp_die.offset.sect_off); if (die) { + /* For .gdb_index version 7 keep track of included TUs. + http://sourceware.org/bugzilla/show_bug.cgi?id=15021. */ + if (dwarf2_per_objfile->index_table != NULL + && dwarf2_per_objfile->index_table->version <= 7) + { + VEC_safe_push (dwarf2_per_cu_ptr, + (*ref_cu)->per_cu->imported_symtabs, + sig_cu->per_cu); + } + *ref_cu = sig_cu; return die; } error (_("Dwarf Error: Cannot find signatured DIE at 0x%x referenced " "from DIE at 0x%x [in module %s]"), - sig_type->type_offset, src_die->offset, objfile->name); + temp_die.offset.sect_off, src_die->offset.sect_off, objfile->name); } /* Given an offset of a signatured type, return its signatured_type. */ @@ -14459,12 +17652,12 @@ follow_die_sig (struct die_info *src_die, struct attribute *attr, static struct signatured_type * lookup_signatured_type_at_offset (struct objfile *objfile, struct dwarf2_section_info *section, - unsigned int offset) + sect_offset offset) { - gdb_byte *info_ptr = section->buffer + offset; + gdb_byte *info_ptr = section->buffer + offset.sect_off; unsigned int length, initial_length_size; unsigned int sig_offset; - struct signatured_type find_entry, *type_sig; + struct signatured_type find_entry, *sig_type; length = read_initial_length (objfile->obfd, info_ptr, &initial_length_size); sig_offset = (initial_length_size @@ -14472,100 +17665,90 @@ lookup_signatured_type_at_offset (struct objfile *objfile, + (initial_length_size == 4 ? 4 : 8) /*debug_abbrev_offset*/ + 1 /*address_size*/); find_entry.signature = bfd_get_64 (objfile->obfd, info_ptr + sig_offset); - type_sig = htab_find (dwarf2_per_objfile->signatured_types, &find_entry); + sig_type = htab_find (dwarf2_per_objfile->signatured_types, &find_entry); /* This is only used to lookup previously recorded types. If we didn't find it, it's our bug. */ - gdb_assert (type_sig != NULL); - gdb_assert (offset == type_sig->per_cu.offset); + gdb_assert (sig_type != NULL); + gdb_assert (offset.sect_off == sig_type->per_cu.offset.sect_off); - return type_sig; + return sig_type; } -/* Read in signatured type at OFFSET and build its CU and die(s). */ +/* Load the DIEs associated with type unit PER_CU into memory. */ static void -read_signatured_type_at_offset (struct objfile *objfile, - struct dwarf2_section_info *sect, - unsigned int offset) +load_full_type_unit (struct dwarf2_per_cu_data *per_cu) { - struct signatured_type *type_sig; + struct signatured_type *sig_type; - dwarf2_read_section (objfile, sect); + /* Caller is responsible for ensuring type_unit_groups don't get here. */ + gdb_assert (! IS_TYPE_UNIT_GROUP (per_cu)); - /* We have the section offset, but we need the signature to do the - hash table lookup. */ - type_sig = lookup_signatured_type_at_offset (objfile, sect, offset); + /* We have the per_cu, but we need the signatured_type. + Fortunately this is an easy translation. */ + gdb_assert (per_cu->is_debug_types); + sig_type = (struct signatured_type *) per_cu; - gdb_assert (type_sig->per_cu.cu == NULL); + gdb_assert (per_cu->cu == NULL); - read_signatured_type (objfile, type_sig); + read_signatured_type (sig_type); - gdb_assert (type_sig->per_cu.cu != NULL); + gdb_assert (per_cu->cu != NULL); } -/* Read in a signatured type and build its CU and DIEs. */ +/* die_reader_func for read_signatured_type. + This is identical to load_full_comp_unit_reader, + but is kept separate for now. */ static void -read_signatured_type (struct objfile *objfile, - struct signatured_type *type_sig) +read_signatured_type_reader (const struct die_reader_specs *reader, + gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data) { - gdb_byte *types_ptr; - struct die_reader_specs reader_specs; - struct dwarf2_cu *cu; - ULONGEST signature; - struct cleanup *back_to, *free_cu_cleanup; - struct dwarf2_section_info *section = type_sig->per_cu.debug_types_section; - - dwarf2_read_section (objfile, section); - types_ptr = section->buffer + type_sig->per_cu.offset; - - gdb_assert (type_sig->per_cu.cu == NULL); - - cu = xmalloc (sizeof (*cu)); - init_one_comp_unit (cu, objfile); - - type_sig->per_cu.cu = cu; - cu->per_cu = &type_sig->per_cu; - - /* If an error occurs while loading, release our storage. */ - free_cu_cleanup = make_cleanup (free_one_comp_unit, cu); - - types_ptr = read_type_comp_unit_head (&cu->header, section, &signature, - types_ptr, objfile->obfd); - gdb_assert (signature == type_sig->signature); - - cu->die_hash - = htab_create_alloc_ex (cu->header.length / 12, - die_hash, - die_eq, - NULL, - &cu->comp_unit_obstack, - hashtab_obstack_allocate, - dummy_obstack_deallocate); - - dwarf2_read_abbrevs (cu->objfile->obfd, cu); - back_to = make_cleanup (dwarf2_free_abbrev_table, cu); + struct dwarf2_cu *cu = reader->cu; - init_cu_die_reader (&reader_specs, cu); + gdb_assert (cu->die_hash == NULL); + cu->die_hash = + htab_create_alloc_ex (cu->header.length / 12, + die_hash, + die_eq, + NULL, + &cu->comp_unit_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); - cu->dies = read_die_and_children (&reader_specs, types_ptr, &types_ptr, - NULL /*parent*/); + if (has_children) + comp_unit_die->child = read_die_and_siblings (reader, info_ptr, + &info_ptr, comp_unit_die); + cu->dies = comp_unit_die; + /* comp_unit_die is not stored in die_hash, no need. */ /* We try not to read any attributes in this function, because not - all objfiles needed for references have been loaded yet, and symbol + all CUs needed for references have been loaded yet, and symbol table processing isn't initialized. But we have to set the CU language, - or we won't be able to build types correctly. */ - prepare_one_comp_unit (cu, cu->dies); + or we won't be able to build types correctly. + Similarly, if we do not read the producer, we can not apply + producer-specific interpretation. */ + prepare_one_comp_unit (cu, cu->dies, language_minimal); +} - do_cleanups (back_to); +/* Read in a signatured type and build its CU and DIEs. + If the type is a stub for the real type in a DWO file, + read in the real type from the DWO file as well. */ + +static void +read_signatured_type (struct signatured_type *sig_type) +{ + struct dwarf2_per_cu_data *per_cu = &sig_type->per_cu; - /* We've successfully allocated this compilation unit. Let our caller - clean it up when finished with it. */ - discard_cleanups (free_cu_cleanup); + gdb_assert (per_cu->is_debug_types); + gdb_assert (per_cu->cu == NULL); - type_sig->per_cu.cu->read_in_chain = dwarf2_per_objfile->read_in_chain; - dwarf2_per_objfile->read_in_chain = &type_sig->per_cu; + init_cutu_and_read_dies (per_cu, NULL, 0, 1, + read_signatured_type_reader, NULL); } /* Decode simple location descriptions. @@ -14593,8 +17776,8 @@ static CORE_ADDR decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; - int i; - int size = blk->size; + size_t i; + size_t size = blk->size; gdb_byte *data = blk->data; CORE_ADDR stack[64]; int stacki; @@ -14790,9 +17973,16 @@ decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu) case DW_OP_GNU_uninit: break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + stack[++stacki] = read_addr_index_from_leb128 (cu, &data[i], + &bytes_read); + i += bytes_read; + break; + default: { - const char *name = dwarf_stack_op_name (op); + const char *name = get_DW_OP_name (op); if (name) complaint (&symfile_complaints, _("unsupported stack op: '%s'"), @@ -14836,17 +18026,6 @@ dwarf_alloc_block (struct dwarf2_cu *cu) return (blk); } -static struct abbrev_info * -dwarf_alloc_abbrev (struct dwarf2_cu *cu) -{ - struct abbrev_info *abbrev; - - abbrev = (struct abbrev_info *) - obstack_alloc (&cu->abbrev_obstack, sizeof (struct abbrev_info)); - memset (abbrev, 0, sizeof (struct abbrev_info)); - return (abbrev); -} - static struct die_info * dwarf_alloc_die (struct dwarf2_cu *cu, int num_attrs) { @@ -14864,12 +18043,12 @@ dwarf_alloc_die (struct dwarf2_cu *cu, int num_attrs) /* Macro support. */ -/* Return the full name of file number I in *LH's file name table. - Use COMP_DIR as the name of the current directory of the - compilation. The result is allocated using xmalloc; the caller is +/* Return file name relative to the compilation directory of file number I in + *LH's file name table. The result is allocated using xmalloc; the caller is responsible for freeing it. */ + static char * -file_full_name (int file, struct line_header *lh, const char *comp_dir) +file_file_name (int file, struct line_header *lh) { /* Is the file number a valid index into the line header's file name table? Remember that file numbers start with one, not zero. */ @@ -14877,31 +18056,10 @@ file_full_name (int file, struct line_header *lh, const char *comp_dir) { struct file_entry *fe = &lh->file_names[file - 1]; - if (IS_ABSOLUTE_PATH (fe->name)) + if (IS_ABSOLUTE_PATH (fe->name) || fe->dir_index == 0) return xstrdup (fe->name); - else - { - const char *dir; - int dir_len; - char *full_name; - - if (fe->dir_index) - dir = lh->include_dirs[fe->dir_index - 1]; - else - dir = comp_dir; - - if (dir) - { - dir_len = strlen (dir); - full_name = xmalloc (dir_len + 1 + strlen (fe->name) + 1); - strcpy (full_name, dir); - full_name[dir_len] = '/'; - strcpy (full_name + dir_len + 1, fe->name); - return full_name; - } - else - return xstrdup (fe->name); - } + return concat (lh->include_dirs[fe->dir_index - 1], SLASH_STRING, + fe->name, NULL); } else { @@ -14910,7 +18068,8 @@ file_full_name (int file, struct line_header *lh, const char *comp_dir) won't be able to find the file by name. */ char fake_name[80]; - sprintf (fake_name, "", file); + xsnprintf (fake_name, sizeof (fake_name), + "", file); complaint (&symfile_complaints, _("bad file number in macro information (%d)"), @@ -14920,6 +18079,27 @@ file_full_name (int file, struct line_header *lh, const char *comp_dir) } } +/* Return the full name of file number I in *LH's file name table. + Use COMP_DIR as the name of the current directory of the + compilation. The result is allocated using xmalloc; the caller is + responsible for freeing it. */ +static char * +file_full_name (int file, struct line_header *lh, const char *comp_dir) +{ + /* Is the file number a valid index into the line header's file name + table? Remember that file numbers start with one, not zero. */ + if (1 <= file && file <= lh->num_file_names) + { + char *relative = file_file_name (file, lh); + + if (IS_ABSOLUTE_PATH (relative) || comp_dir == NULL) + return relative; + return reconcat (relative, comp_dir, SLASH_STRING, relative, NULL); + } + else + return file_file_name (file, lh); +} + static struct macro_source_file * macro_start_file (int file, int line, @@ -14927,23 +18107,27 @@ macro_start_file (int file, int line, const char *comp_dir, struct line_header *lh, struct objfile *objfile) { - /* The full name of this source file. */ - char *full_name = file_full_name (file, lh, comp_dir); + /* File name relative to the compilation directory of this source file. */ + char *file_name = file_file_name (file, lh); /* We don't create a macro table for this compilation unit at all until we actually get a filename. */ if (! pending_macros) - pending_macros = new_macro_table (&objfile->objfile_obstack, - objfile->macro_cache); + pending_macros = new_macro_table (&objfile->per_bfd->storage_obstack, + objfile->per_bfd->macro_cache, + comp_dir); if (! current_file) - /* If we have no current file, then this must be the start_file - directive for the compilation unit's main source file. */ - current_file = macro_set_main (pending_macros, full_name); + { + /* If we have no current file, then this must be the start_file + directive for the compilation unit's main source file. */ + current_file = macro_set_main (pending_macros, file_name); + macro_define_special (pending_macros); + } else - current_file = macro_include (current_file, line, full_name); + current_file = macro_include (current_file, line, file_name); - xfree (full_name); + xfree (file_name); return current_file; } @@ -15124,7 +18308,7 @@ parse_macro_definition (struct macro_source_file *file, int line, Returns the new pointer. */ static gdb_byte * -skip_form_bytes (bfd *abfd, gdb_byte *bytes, +skip_form_bytes (bfd *abfd, gdb_byte *bytes, gdb_byte *buffer_end, enum dwarf_form form, unsigned int offset_size, struct dwarf2_section_info *section) @@ -15157,6 +18341,7 @@ skip_form_bytes (bfd *abfd, gdb_byte *bytes, case DW_FORM_sec_offset: case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: bytes += offset_size; break; @@ -15177,7 +18362,14 @@ skip_form_bytes (bfd *abfd, gdb_byte *bytes, case DW_FORM_sdata: case DW_FORM_udata: - bytes = skip_leb128 (abfd, bytes); + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + bytes = (gdb_byte *) gdb_skip_leb128 (bytes, buffer_end); + if (bytes == NULL) + { + dwarf2_section_buffer_overflow_complaint (section); + return NULL; + } break; default: @@ -15201,7 +18393,7 @@ skip_form_bytes (bfd *abfd, gdb_byte *bytes, static gdb_byte * skip_unknown_opcode (unsigned int opcode, gdb_byte **opcode_definitions, - gdb_byte *mac_ptr, + gdb_byte *mac_ptr, gdb_byte *mac_end, bfd *abfd, unsigned int offset_size, struct dwarf2_section_info *section) @@ -15224,7 +18416,8 @@ skip_unknown_opcode (unsigned int opcode, for (i = 0; i < arg; ++i) { - mac_ptr = skip_form_bytes (abfd, mac_ptr, defn[i], offset_size, section); + mac_ptr = skip_form_bytes (abfd, mac_ptr, mac_end, defn[i], offset_size, + section); if (mac_ptr == NULL) { /* skip_form_bytes already issued the complaint. */ @@ -15297,16 +18490,17 @@ dwarf_parse_macro_header (gdb_byte **opcode_definitions, } /* A helper for dwarf_decode_macros that handles the GNU extensions, - including DW_GNU_MACINFO_transparent_include. */ + including DW_MACRO_GNU_transparent_include. */ static void dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, struct macro_source_file *current_file, - struct line_header *lh, char *comp_dir, + struct line_header *lh, const char *comp_dir, struct dwarf2_section_info *section, - int section_is_gnu, + int section_is_gnu, int section_is_dwz, unsigned int offset_size, - struct objfile *objfile) + struct objfile *objfile, + htab_t include_hash) { enum dwarf_macro_record_type macinfo_type; int at_commandline; @@ -15334,7 +18528,7 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, /* Do we at least have room for a macinfo type byte? */ if (mac_ptr >= mac_end) { - dwarf2_macros_too_long_complaint (section); + dwarf2_section_buffer_overflow_complaint (section); break; } @@ -15354,6 +18548,8 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, case DW_MACRO_GNU_undef: case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_GNU_define_indirect_alt: + case DW_MACRO_GNU_undef_indirect_alt: { unsigned int bytes_read; int line; @@ -15376,11 +18572,21 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, str_offset = read_offset_1 (abfd, mac_ptr, offset_size); mac_ptr += offset_size; - body = read_indirect_string_at_offset (abfd, str_offset); + if (macinfo_type == DW_MACRO_GNU_define_indirect_alt + || macinfo_type == DW_MACRO_GNU_undef_indirect_alt + || section_is_dwz) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + body = read_indirect_string_from_dwz (dwz, str_offset); + } + else + body = read_indirect_string_at_offset (abfd, str_offset); } is_define = (macinfo_type == DW_MACRO_GNU_define - || macinfo_type == DW_MACRO_GNU_define_indirect); + || macinfo_type == DW_MACRO_GNU_define_indirect + || macinfo_type == DW_MACRO_GNU_define_indirect_alt); if (! current_file) { /* DWARF violation as no main source is present. */ @@ -15404,7 +18610,8 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, else { gdb_assert (macinfo_type == DW_MACRO_GNU_undef - || macinfo_type == DW_MACRO_GNU_undef_indirect); + || macinfo_type == DW_MACRO_GNU_undef_indirect + || macinfo_type == DW_MACRO_GNU_undef_indirect_alt); macro_undef (current_file, line, body); } } @@ -15461,7 +18668,7 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, /* Do we at least have room for a macinfo type byte? */ if (mac_ptr >= mac_end) { - dwarf2_macros_too_long_complaint (section); + dwarf2_section_buffer_overflow_complaint (section); return; } @@ -15479,18 +18686,56 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, break; case DW_MACRO_GNU_transparent_include: + case DW_MACRO_GNU_transparent_include_alt: { LONGEST offset; + void **slot; + bfd *include_bfd = abfd; + struct dwarf2_section_info *include_section = section; + struct dwarf2_section_info alt_section; + gdb_byte *include_mac_end = mac_end; + int is_dwz = section_is_dwz; + gdb_byte *new_mac_ptr; offset = read_offset_1 (abfd, mac_ptr, offset_size); mac_ptr += offset_size; - dwarf_decode_macro_bytes (abfd, - section->buffer + offset, - mac_end, current_file, - lh, comp_dir, - section, section_is_gnu, - offset_size, objfile); + if (macinfo_type == DW_MACRO_GNU_transparent_include_alt) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + dwarf2_read_section (dwarf2_per_objfile->objfile, + &dwz->macro); + + include_bfd = dwz->macro.asection->owner; + include_section = &dwz->macro; + include_mac_end = dwz->macro.buffer + dwz->macro.size; + is_dwz = 1; + } + + new_mac_ptr = include_section->buffer + offset; + slot = htab_find_slot (include_hash, new_mac_ptr, INSERT); + + if (*slot != NULL) + { + /* This has actually happened; see + http://sourceware.org/bugzilla/show_bug.cgi?id=13568. */ + complaint (&symfile_complaints, + _("recursive DW_MACRO_GNU_transparent_include in " + ".debug_macro section")); + } + else + { + *slot = new_mac_ptr; + + dwarf_decode_macro_bytes (include_bfd, new_mac_ptr, + include_mac_end, current_file, + lh, comp_dir, + section, section_is_gnu, is_dwz, + offset_size, objfile, include_hash); + + htab_remove_elt (include_hash, new_mac_ptr); + } } break; @@ -15512,7 +18757,7 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, default: mac_ptr = skip_unknown_opcode (macinfo_type, opcode_definitions, - mac_ptr, abfd, offset_size, + mac_ptr, mac_end, abfd, offset_size, section); if (mac_ptr == NULL) return; @@ -15522,25 +18767,57 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, } static void -dwarf_decode_macros (struct line_header *lh, unsigned int offset, - char *comp_dir, bfd *abfd, - struct dwarf2_cu *cu, - struct dwarf2_section_info *section, - int section_is_gnu) +dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset, + const char *comp_dir, int section_is_gnu) { + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct line_header *lh = cu->line_header; + bfd *abfd; gdb_byte *mac_ptr, *mac_end; struct macro_source_file *current_file = 0; enum dwarf_macro_record_type macinfo_type; unsigned int offset_size = cu->header.offset_size; gdb_byte *opcode_definitions[256]; + struct cleanup *cleanup; + htab_t include_hash; + void **slot; + struct dwarf2_section_info *section; + const char *section_name; - dwarf2_read_section (dwarf2_per_objfile->objfile, section); + if (cu->dwo_unit != NULL) + { + if (section_is_gnu) + { + section = &cu->dwo_unit->dwo_file->sections.macro; + section_name = ".debug_macro.dwo"; + } + else + { + section = &cu->dwo_unit->dwo_file->sections.macinfo; + section_name = ".debug_macinfo.dwo"; + } + } + else + { + if (section_is_gnu) + { + section = &dwarf2_per_objfile->macro; + section_name = ".debug_macro"; + } + else + { + section = &dwarf2_per_objfile->macinfo; + section_name = ".debug_macinfo"; + } + } + + dwarf2_read_section (objfile, section); if (section->buffer == NULL) { - complaint (&symfile_complaints, _("missing %s section"), - section->asection->name); + complaint (&symfile_complaints, _("missing %s section"), section_name); return; } + abfd = section->asection->owner; /* First pass: Find the name of the base filename. This filename is needed in order to process all macros whose definition @@ -15611,7 +18888,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, mac_ptr += bytes_read; current_file = macro_start_file (file, line, current_file, - comp_dir, lh, cu->objfile); + comp_dir, lh, objfile); } break; @@ -15621,6 +18898,8 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_GNU_define_indirect_alt: + case DW_MACRO_GNU_undef_indirect_alt: { unsigned int bytes_read; @@ -15631,6 +18910,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, break; case DW_MACRO_GNU_transparent_include: + case DW_MACRO_GNU_transparent_include_alt: /* Note that, according to the spec, a transparent include chain cannot call DW_MACRO_GNU_start_file. So, we can just skip this opcode. */ @@ -15652,7 +18932,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, default: mac_ptr = skip_unknown_opcode (macinfo_type, opcode_definitions, - mac_ptr, abfd, offset_size, + mac_ptr, mac_end, abfd, offset_size, section); if (mac_ptr == NULL) return; @@ -15666,13 +18946,22 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, command-line macro definitions/undefinitions. This flag is unset when we reach the first DW_MACINFO_start_file entry. */ - dwarf_decode_macro_bytes (abfd, section->buffer + offset, mac_end, - current_file, lh, comp_dir, section, section_is_gnu, - offset_size, cu->objfile); + include_hash = htab_create_alloc (1, htab_hash_pointer, htab_eq_pointer, + NULL, xcalloc, xfree); + cleanup = make_cleanup_htab_delete (include_hash); + mac_ptr = section->buffer + offset; + slot = htab_find_slot (include_hash, mac_ptr, INSERT); + *slot = mac_ptr; + dwarf_decode_macro_bytes (abfd, mac_ptr, mac_end, + current_file, lh, comp_dir, section, + section_is_gnu, 0, + offset_size, objfile, include_hash); + do_cleanups (cleanup); } /* Check if the attribute's form is a DW_FORM_block* if so return true else false. */ + static int attr_form_is_block (struct attribute *attr) { @@ -15692,6 +18981,7 @@ attr_form_is_block (struct attribute *attr) may have a value that belongs to more than one of these classes; it would be ambiguous if we did, because we use the same forms for all of them. */ + static int attr_form_is_section_offset (struct attribute *attr) { @@ -15700,7 +18990,6 @@ attr_form_is_section_offset (struct attribute *attr) || attr->form == DW_FORM_sec_offset); } - /* Return non-zero if ATTR's value falls in the 'constant' class, or zero otherwise. When this function returns true, you can apply dwarf2_get_attr_constant_value to it. @@ -15713,6 +19002,7 @@ attr_form_is_section_offset (struct attribute *attr) that, if an attribute's can be either a constant or one of the section offset classes, DW_FORM_data4 and DW_FORM_data8 should be taken as section offsets, not constants. */ + static int attr_form_is_constant (struct attribute *attr) { @@ -15730,6 +19020,17 @@ attr_form_is_constant (struct attribute *attr) } } +/* Return the .debug_loc section to use for CU. + For DWO files use .debug_loc.dwo. */ + +static struct dwarf2_section_info * +cu_debug_loc_section (struct dwarf2_cu *cu) +{ + if (cu->dwo_unit) + return &cu->dwo_unit->dwo_file->sections.loc; + return &dwarf2_per_objfile->loc; +} + /* A helper function that fills in a dwarf2_loclist_baton. */ static void @@ -15737,32 +19038,36 @@ fill_in_loclist_baton (struct dwarf2_cu *cu, struct dwarf2_loclist_baton *baton, struct attribute *attr) { - dwarf2_read_section (dwarf2_per_objfile->objfile, - &dwarf2_per_objfile->loc); + struct dwarf2_section_info *section = cu_debug_loc_section (cu); + + dwarf2_read_section (dwarf2_per_objfile->objfile, section); baton->per_cu = cu->per_cu; gdb_assert (baton->per_cu); /* We don't know how long the location list is, but make sure we don't run off the edge of the section. */ - baton->size = dwarf2_per_objfile->loc.size - DW_UNSND (attr); - baton->data = dwarf2_per_objfile->loc.buffer + DW_UNSND (attr); + baton->size = section->size - DW_UNSND (attr); + baton->data = section->buffer + DW_UNSND (attr); baton->base_address = cu->base_address; + baton->from_dwo = cu->dwo_unit != NULL; } static void dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu) { + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_section_info *section = cu_debug_loc_section (cu); + if (attr_form_is_section_offset (attr) - /* ".debug_loc" may not exist at all, or the offset may be outside + /* .debug_loc{,.dwo} may not exist at all, or the offset may be outside the section. If so, fall through to the complaint in the other branch. */ - && DW_UNSND (attr) < dwarf2_section_size (dwarf2_per_objfile->objfile, - &dwarf2_per_objfile->loc)) + && DW_UNSND (attr) < dwarf2_section_size (objfile, section)) { struct dwarf2_loclist_baton *baton; - baton = obstack_alloc (&cu->objfile->objfile_obstack, + baton = obstack_alloc (&objfile->objfile_obstack, sizeof (struct dwarf2_loclist_baton)); fill_in_loclist_baton (cu, baton, attr); @@ -15779,7 +19084,7 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, { struct dwarf2_locexpr_baton *baton; - baton = obstack_alloc (&cu->objfile->objfile_obstack, + baton = obstack_alloc (&objfile->objfile_obstack, sizeof (struct dwarf2_locexpr_baton)); baton->per_cu = cu->per_cu; gdb_assert (baton->per_cu); @@ -15831,26 +19136,22 @@ static const struct comp_unit_head * per_cu_header_read_in (struct comp_unit_head *cu_headerp, struct dwarf2_per_cu_data *per_cu) { - struct objfile *objfile; - struct dwarf2_per_objfile *per_objfile; gdb_byte *info_ptr; if (per_cu->cu) return &per_cu->cu->header; - objfile = per_cu->objfile; - per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); - info_ptr = per_objfile->info.buffer + per_cu->offset; + info_ptr = per_cu->info_or_types_section->buffer + per_cu->offset.sect_off; memset (cu_headerp, 0, sizeof (*cu_headerp)); - read_comp_unit_head (cu_headerp, info_ptr, objfile->obfd); + read_comp_unit_head (cu_headerp, info_ptr, per_cu->objfile->obfd); return cu_headerp; } /* Return the address size given in the compilation unit header for CU. */ -CORE_ADDR +int dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *per_cu) { struct comp_unit_head cu_header_local; @@ -15907,73 +19208,72 @@ dwarf2_per_cu_text_offset (struct dwarf2_per_cu_data *per_cu) the DIE at OFFSET. Raises an error on failure. */ static struct dwarf2_per_cu_data * -dwarf2_find_containing_comp_unit (unsigned int offset, +dwarf2_find_containing_comp_unit (sect_offset offset, + unsigned int offset_in_dwz, struct objfile *objfile) { struct dwarf2_per_cu_data *this_cu; int low, high; + const sect_offset *cu_off; low = 0; high = dwarf2_per_objfile->n_comp_units - 1; while (high > low) { + struct dwarf2_per_cu_data *mid_cu; int mid = low + (high - low) / 2; - if (dwarf2_per_objfile->all_comp_units[mid]->offset >= offset) + mid_cu = dwarf2_per_objfile->all_comp_units[mid]; + cu_off = &mid_cu->offset; + if (mid_cu->is_dwz > offset_in_dwz + || (mid_cu->is_dwz == offset_in_dwz + && cu_off->sect_off >= offset.sect_off)) high = mid; else low = mid + 1; } gdb_assert (low == high); - if (dwarf2_per_objfile->all_comp_units[low]->offset > offset) + this_cu = dwarf2_per_objfile->all_comp_units[low]; + cu_off = &this_cu->offset; + if (this_cu->is_dwz != offset_in_dwz || cu_off->sect_off > offset.sect_off) { - if (low == 0) + if (low == 0 || this_cu->is_dwz != offset_in_dwz) error (_("Dwarf Error: could not find partial DIE containing " "offset 0x%lx [in module %s]"), - (long) offset, bfd_get_filename (objfile->obfd)); + (long) offset.sect_off, bfd_get_filename (objfile->obfd)); - gdb_assert (dwarf2_per_objfile->all_comp_units[low-1]->offset <= offset); + gdb_assert (dwarf2_per_objfile->all_comp_units[low-1]->offset.sect_off + <= offset.sect_off); return dwarf2_per_objfile->all_comp_units[low-1]; } else { this_cu = dwarf2_per_objfile->all_comp_units[low]; if (low == dwarf2_per_objfile->n_comp_units - 1 - && offset >= this_cu->offset + this_cu->length) - error (_("invalid dwarf2 offset %u"), offset); - gdb_assert (offset < this_cu->offset + this_cu->length); + && offset.sect_off >= this_cu->offset.sect_off + this_cu->length) + error (_("invalid dwarf2 offset %u"), offset.sect_off); + gdb_assert (offset.sect_off < this_cu->offset.sect_off + this_cu->length); return this_cu; } } -/* Locate the compilation unit from OBJFILE which is located at exactly - OFFSET. Raises an error on failure. */ - -static struct dwarf2_per_cu_data * -dwarf2_find_comp_unit (unsigned int offset, struct objfile *objfile) -{ - struct dwarf2_per_cu_data *this_cu; - - this_cu = dwarf2_find_containing_comp_unit (offset, objfile); - if (this_cu->offset != offset) - error (_("no compilation unit with offset %u."), offset); - return this_cu; -} - -/* Initialize dwarf2_cu CU for OBJFILE in a pre-allocated space. */ +/* Initialize dwarf2_cu CU, owned by PER_CU. */ static void -init_one_comp_unit (struct dwarf2_cu *cu, struct objfile *objfile) +init_one_comp_unit (struct dwarf2_cu *cu, struct dwarf2_per_cu_data *per_cu) { memset (cu, 0, sizeof (*cu)); - cu->objfile = objfile; + per_cu->cu = cu; + cu->per_cu = per_cu; + cu->objfile = per_cu->objfile; obstack_init (&cu->comp_unit_obstack); } /* Initialize basic fields of dwarf_cu CU according to DIE COMP_UNIT_DIE. */ static void -prepare_one_comp_unit (struct dwarf2_cu *cu, struct die_info *comp_unit_die) +prepare_one_comp_unit (struct dwarf2_cu *cu, struct die_info *comp_unit_die, + enum language pretend_language) { struct attribute *attr; @@ -15983,9 +19283,13 @@ prepare_one_comp_unit (struct dwarf2_cu *cu, struct die_info *comp_unit_die) set_cu_language (DW_UNSND (attr), cu); else { - cu->language = language_minimal; + cu->language = pretend_language; cu->language_defn = language_def (cu->language); } + + attr = dwarf2_attr (comp_unit_die, DW_AT_producer, cu); + if (attr) + cu->producer = DW_STRING (attr); } /* Release one cached compilation unit, CU. We unlink it from the tree @@ -15995,12 +19299,12 @@ prepare_one_comp_unit (struct dwarf2_cu *cu, struct die_info *comp_unit_die) cleanup routine. */ static void -free_one_comp_unit (void *data) +free_heap_comp_unit (void *data) { struct dwarf2_cu *cu = data; - if (cu->per_cu != NULL) - cu->per_cu->cu = NULL; + gdb_assert (cu->per_cu != NULL); + cu->per_cu->cu = NULL; cu->per_cu = NULL; obstack_free (&cu->comp_unit_obstack, NULL); @@ -16010,30 +19314,19 @@ free_one_comp_unit (void *data) /* This cleanup function is passed the address of a dwarf2_cu on the stack when we're finished with it. We can't free the pointer itself, but be - sure to unlink it from the cache. Also release any associated storage - and perform cache maintenance. - - Only used during partial symbol parsing. */ + sure to unlink it from the cache. Also release any associated storage. */ static void free_stack_comp_unit (void *data) { struct dwarf2_cu *cu = data; + gdb_assert (cu->per_cu != NULL); + cu->per_cu->cu = NULL; + cu->per_cu = NULL; + obstack_free (&cu->comp_unit_obstack, NULL); cu->partial_dies = NULL; - - if (cu->per_cu != NULL) - { - /* This compilation unit is on the stack in our caller, so we - should not xfree it. Just unlink it. */ - cu->per_cu->cu = NULL; - cu->per_cu = NULL; - - /* If we had a per-cu pointer, then we may have other compilation - units loaded, so age them now. */ - age_cached_comp_units (); - } } /* Free all cached compilation units. */ @@ -16051,7 +19344,7 @@ free_cached_comp_units (void *data) next_cu = per_cu->cu->read_in_chain; - free_one_comp_unit (per_cu->cu); + free_heap_comp_unit (per_cu->cu); *last_chain = next_cu; per_cu = next_cu; @@ -16086,7 +19379,7 @@ age_cached_comp_units (void) if (!per_cu->cu->mark) { - free_one_comp_unit (per_cu->cu); + free_heap_comp_unit (per_cu->cu); *last_chain = next_cu; } else @@ -16099,7 +19392,7 @@ age_cached_comp_units (void) /* Remove a single compilation unit from the cache. */ static void -free_one_cached_comp_unit (void *target_cu) +free_one_cached_comp_unit (struct dwarf2_per_cu_data *target_per_cu) { struct dwarf2_per_cu_data *per_cu, **last_chain; @@ -16111,9 +19404,10 @@ free_one_cached_comp_unit (void *target_cu) next_cu = per_cu->cu->read_in_chain; - if (per_cu->cu == target_cu) + if (per_cu == target_per_cu) { - free_one_comp_unit (per_cu->cu); + free_heap_comp_unit (per_cu->cu); + per_cu->cu = NULL; *last_chain = next_cu; break; } @@ -16143,35 +19437,45 @@ dwarf2_free_objfile (struct objfile *objfile) /* Everything else should be on the objfile obstack. */ } -/* A pair of DIE offset and GDB type pointer. We store these - in a hash table separate from the DIEs, and preserve them - when the DIEs are flushed out of cache. */ +/* A set of CU "per_cu" pointer, DIE offset, and GDB type pointer. + We store these in a hash table separate from the DIEs, and preserve them + when the DIEs are flushed out of cache. + + The CU "per_cu" pointer is needed because offset alone is not enough to + uniquely identify the type. A file may have multiple .debug_types sections, + or the type may come from a DWO file. We have to use something in + dwarf2_per_cu_data (or the pointer to it) because we can enter the lookup + routine, get_die_type_at_offset, from outside this file, and thus won't + necessarily have PER_CU->cu. Fortunately, PER_CU is stable for the life + of the objfile. */ -struct dwarf2_offset_and_type +struct dwarf2_per_cu_offset_and_type { - unsigned int offset; + const struct dwarf2_per_cu_data *per_cu; + sect_offset offset; struct type *type; }; -/* Hash function for a dwarf2_offset_and_type. */ +/* Hash function for a dwarf2_per_cu_offset_and_type. */ static hashval_t -offset_and_type_hash (const void *item) +per_cu_offset_and_type_hash (const void *item) { - const struct dwarf2_offset_and_type *ofs = item; + const struct dwarf2_per_cu_offset_and_type *ofs = item; - return ofs->offset; + return (uintptr_t) ofs->per_cu + ofs->offset.sect_off; } -/* Equality function for a dwarf2_offset_and_type. */ +/* Equality function for a dwarf2_per_cu_offset_and_type. */ static int -offset_and_type_eq (const void *item_lhs, const void *item_rhs) +per_cu_offset_and_type_eq (const void *item_lhs, const void *item_rhs) { - const struct dwarf2_offset_and_type *ofs_lhs = item_lhs; - const struct dwarf2_offset_and_type *ofs_rhs = item_rhs; + const struct dwarf2_per_cu_offset_and_type *ofs_lhs = item_lhs; + const struct dwarf2_per_cu_offset_and_type *ofs_rhs = item_rhs; - return ofs_lhs->offset == ofs_rhs->offset; + return (ofs_lhs->per_cu == ofs_rhs->per_cu + && ofs_lhs->offset.sect_off == ofs_rhs->offset.sect_off); } /* Set the type associated with DIE to TYPE. Save it in CU's hash @@ -16195,9 +19499,8 @@ offset_and_type_eq (const void *item_lhs, const void *item_rhs) static struct type * set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu) { - struct dwarf2_offset_and_type **slot, ofs; + struct dwarf2_per_cu_offset_and_type **slot, ofs; struct objfile *objfile = cu->objfile; - htab_t *type_hash_ptr; /* For Ada types, make sure that the gnat-specific data is always initialized (if not already set). There are a few types where @@ -16212,55 +19515,47 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu) && !HAVE_GNAT_AUX_INFO (type)) INIT_GNAT_SPECIFIC (type); - if (cu->per_cu->debug_types_section) - type_hash_ptr = &dwarf2_per_objfile->debug_types_type_hash; - else - type_hash_ptr = &dwarf2_per_objfile->debug_info_type_hash; - - if (*type_hash_ptr == NULL) + if (dwarf2_per_objfile->die_type_hash == NULL) { - *type_hash_ptr - = htab_create_alloc_ex (127, - offset_and_type_hash, - offset_and_type_eq, - NULL, - &objfile->objfile_obstack, - hashtab_obstack_allocate, - dummy_obstack_deallocate); + dwarf2_per_objfile->die_type_hash = + htab_create_alloc_ex (127, + per_cu_offset_and_type_hash, + per_cu_offset_and_type_eq, + NULL, + &objfile->objfile_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); } + ofs.per_cu = cu->per_cu; ofs.offset = die->offset; ofs.type = type; - slot = (struct dwarf2_offset_and_type **) - htab_find_slot_with_hash (*type_hash_ptr, &ofs, ofs.offset, INSERT); + slot = (struct dwarf2_per_cu_offset_and_type **) + htab_find_slot (dwarf2_per_objfile->die_type_hash, &ofs, INSERT); if (*slot) complaint (&symfile_complaints, _("A problem internal to GDB: DIE 0x%x has type already set"), - die->offset); + die->offset.sect_off); *slot = obstack_alloc (&objfile->objfile_obstack, sizeof (**slot)); **slot = ofs; return type; } -/* Look up the type for the die at DIE_OFFSET in the appropriate type_hash +/* Look up the type for the die at OFFSET in the appropriate type_hash table, or return NULL if the die does not have a saved type. */ static struct type * -get_die_type_at_offset (unsigned int offset, +get_die_type_at_offset (sect_offset offset, struct dwarf2_per_cu_data *per_cu) { - struct dwarf2_offset_and_type *slot, ofs; - htab_t type_hash; + struct dwarf2_per_cu_offset_and_type *slot, ofs; - if (per_cu->debug_types_section) - type_hash = dwarf2_per_objfile->debug_types_type_hash; - else - type_hash = dwarf2_per_objfile->debug_info_type_hash; - if (type_hash == NULL) + if (dwarf2_per_objfile->die_type_hash == NULL) return NULL; + ofs.per_cu = per_cu; ofs.offset = offset; - slot = htab_find_with_hash (type_hash, &ofs, ofs.offset); + slot = htab_find (dwarf2_per_objfile->die_type_hash, &ofs); if (slot) return slot->type; else @@ -16354,7 +19649,7 @@ partial_die_hash (const void *item) { const struct partial_die_info *part_die = item; - return part_die->offset; + return part_die->offset.sect_off; } /* Trivial comparison function for partial_die_info structures: two DIEs @@ -16366,7 +19661,7 @@ partial_die_eq (const void *item_lhs, const void *item_rhs) const struct partial_die_info *part_die_lhs = item_lhs; const struct partial_die_info *part_die_rhs = item_rhs; - return part_die_lhs->offset == part_die_rhs->offset; + return part_die_lhs->offset.sect_off == part_die_rhs->offset.sect_off; } static struct cmd_list_element *set_dwarf2_cmdlist; @@ -16384,54 +19679,31 @@ show_dwarf2_cmd (char *args, int from_tty) cmd_show_list (show_dwarf2_cmdlist, from_tty, ""); } -/* If section described by INFO was mmapped, munmap it now. */ - -static void -munmap_section_buffer (struct dwarf2_section_info *info) -{ - if (info->map_addr != NULL) - { -#ifdef HAVE_MMAP - int res; - - res = munmap (info->map_addr, info->map_len); - gdb_assert (res == 0); -#else - /* Without HAVE_MMAP, we should never be here to begin with. */ - gdb_assert_not_reached ("no mmap support"); -#endif - } -} - -/* munmap debug sections for OBJFILE, if necessary. */ +/* Free data associated with OBJFILE, if necessary. */ static void dwarf2_per_objfile_free (struct objfile *objfile, void *d) { struct dwarf2_per_objfile *data = d; int ix; - struct dwarf2_section_info *section; - /* This is sorted according to the order they're defined in to make it easier - to keep in sync. */ - munmap_section_buffer (&data->info); - munmap_section_buffer (&data->abbrev); - munmap_section_buffer (&data->line); - munmap_section_buffer (&data->loc); - munmap_section_buffer (&data->macinfo); - munmap_section_buffer (&data->macro); - munmap_section_buffer (&data->str); - munmap_section_buffer (&data->ranges); - munmap_section_buffer (&data->frame); - munmap_section_buffer (&data->eh_frame); - munmap_section_buffer (&data->gdb_index); + for (ix = 0; ix < dwarf2_per_objfile->n_comp_units; ++ix) + VEC_free (dwarf2_per_cu_ptr, + dwarf2_per_objfile->all_comp_units[ix]->imported_symtabs); - for (ix = 0; - VEC_iterate (dwarf2_section_info_def, data->types, ix, section); - ++ix) - munmap_section_buffer (section); + for (ix = 0; ix < dwarf2_per_objfile->n_type_units; ++ix) + VEC_free (dwarf2_per_cu_ptr, + dwarf2_per_objfile->all_type_units[ix]->per_cu.imported_symtabs); VEC_free (dwarf2_section_info_def, data->types); + + if (data->dwo_files) + free_dwo_files (data->dwo_files, objfile); + if (data->dwp_file) + gdb_bfd_unref (data->dwp_file->dbfd); + + if (data->dwz_file && data->dwz_file->dwz_bfd) + gdb_bfd_unref (data->dwz_file->dwz_bfd); } @@ -16638,14 +19910,17 @@ hash_expand (struct mapped_symtab *symtab) xfree (old_entries); } -/* Add an entry to SYMTAB. NAME is the name of the symbol. CU_INDEX - is the index of the CU in which the symbol appears. */ +/* Add an entry to SYMTAB. NAME is the name of the symbol. + CU_INDEX is the index of the CU in which the symbol appears. + IS_STATIC is one if the symbol is static, otherwise zero (global). */ static void add_index_entry (struct mapped_symtab *symtab, const char *name, + int is_static, gdb_index_symbol_kind kind, offset_type cu_index) { struct symtab_index_entry **slot; + offset_type cu_index_and_attrs; ++symtab->n_elements; if (4 * symtab->n_elements / 3 >= symtab->size) @@ -16656,13 +19931,76 @@ add_index_entry (struct mapped_symtab *symtab, const char *name, { *slot = XNEW (struct symtab_index_entry); (*slot)->name = name; + /* index_offset is set later. */ (*slot)->cu_indices = NULL; } - /* Don't push an index twice. Due to how we add entries we only - have to check the last one. */ - if (VEC_empty (offset_type, (*slot)->cu_indices) - || VEC_last (offset_type, (*slot)->cu_indices) != cu_index) - VEC_safe_push (offset_type, (*slot)->cu_indices, cu_index); + + cu_index_and_attrs = 0; + DW2_GDB_INDEX_CU_SET_VALUE (cu_index_and_attrs, cu_index); + DW2_GDB_INDEX_SYMBOL_STATIC_SET_VALUE (cu_index_and_attrs, is_static); + DW2_GDB_INDEX_SYMBOL_KIND_SET_VALUE (cu_index_and_attrs, kind); + + /* We don't want to record an index value twice as we want to avoid the + duplication. + We process all global symbols and then all static symbols + (which would allow us to avoid the duplication by only having to check + the last entry pushed), but a symbol could have multiple kinds in one CU. + To keep things simple we don't worry about the duplication here and + sort and uniqufy the list after we've processed all symbols. */ + VEC_safe_push (offset_type, (*slot)->cu_indices, cu_index_and_attrs); +} + +/* qsort helper routine for uniquify_cu_indices. */ + +static int +offset_type_compare (const void *ap, const void *bp) +{ + offset_type a = *(offset_type *) ap; + offset_type b = *(offset_type *) bp; + + return (a > b) - (b > a); +} + +/* Sort and remove duplicates of all symbols' cu_indices lists. */ + +static void +uniquify_cu_indices (struct mapped_symtab *symtab) +{ + int i; + + for (i = 0; i < symtab->size; ++i) + { + struct symtab_index_entry *entry = symtab->data[i]; + + if (entry + && entry->cu_indices != NULL) + { + unsigned int next_to_insert, next_to_check; + offset_type last_value; + + qsort (VEC_address (offset_type, entry->cu_indices), + VEC_length (offset_type, entry->cu_indices), + sizeof (offset_type), offset_type_compare); + + last_value = VEC_index (offset_type, entry->cu_indices, 0); + next_to_insert = 1; + for (next_to_check = 1; + next_to_check < VEC_length (offset_type, entry->cu_indices); + ++next_to_check) + { + if (VEC_index (offset_type, entry->cu_indices, next_to_check) + != last_value) + { + last_value = VEC_index (offset_type, entry->cu_indices, + next_to_check); + VEC_replace (offset_type, entry->cu_indices, next_to_insert, + last_value); + ++next_to_insert; + } + } + VEC_truncate (offset_type, entry->cu_indices, next_to_insert); + } + } } /* Add a vector of indices to the constant pool. */ @@ -16821,8 +20159,6 @@ add_address_entry_worker (void *datap, CORE_ADDR start_addr, void *obj) { struct addrmap_index_data *data = datap; struct partial_symtab *pst = obj; - offset_type cu_index; - void **slot; if (data->previous_valid) add_address_entry (data->objfile, data->addr_obstack, @@ -16878,6 +20214,44 @@ write_address_map (struct objfile *objfile, struct obstack *obstack, addrmap_index_data.previous_cu_index); } +/* Return the symbol kind of PSYM. */ + +static gdb_index_symbol_kind +symbol_kind (struct partial_symbol *psym) +{ + domain_enum domain = PSYMBOL_DOMAIN (psym); + enum address_class aclass = PSYMBOL_CLASS (psym); + + switch (domain) + { + case VAR_DOMAIN: + switch (aclass) + { + case LOC_BLOCK: + return GDB_INDEX_SYMBOL_KIND_FUNCTION; + case LOC_TYPEDEF: + return GDB_INDEX_SYMBOL_KIND_TYPE; + case LOC_COMPUTED: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + case LOC_STATIC: + return GDB_INDEX_SYMBOL_KIND_VARIABLE; + case LOC_CONST: + /* Note: It's currently impossible to recognize psyms as enum values + short of reading the type info. For now punt. */ + return GDB_INDEX_SYMBOL_KIND_VARIABLE; + default: + /* There are other LOC_FOO values that one might want to classify + as variables, but dwarf2read.c doesn't currently use them. */ + return GDB_INDEX_SYMBOL_KIND_OTHER; + } + case STRUCT_DOMAIN: + return GDB_INDEX_SYMBOL_KIND_TYPE; + default: + return GDB_INDEX_SYMBOL_KIND_OTHER; + } +} + /* Add a list of partial symbols to SYMTAB. */ static void @@ -16890,29 +20264,21 @@ write_psymbols (struct mapped_symtab *symtab, { for (; count-- > 0; ++psymp) { - void **slot, *lookup; + struct partial_symbol *psym = *psymp; + void **slot; - if (SYMBOL_LANGUAGE (*psymp) == language_ada) + if (SYMBOL_LANGUAGE (psym) == language_ada) error (_("Ada is not currently supported by the index")); - /* We only want to add a given psymbol once. However, we also - want to account for whether it is global or static. So, we - may add it twice, using slightly different values. */ - if (is_static) - { - uintptr_t val = 1 | (uintptr_t) *psymp; - - lookup = (void *) val; - } - else - lookup = *psymp; - /* Only add a given psymbol once. */ - slot = htab_find_slot (psyms_seen, lookup, INSERT); + slot = htab_find_slot (psyms_seen, psym, INSERT); if (!*slot) { - *slot = lookup; - add_index_entry (symtab, SYMBOL_NATURAL_NAME (*psymp), cu_index); + gdb_index_symbol_kind kind = symbol_kind (psym); + + *slot = psym; + add_index_entry (symtab, SYMBOL_SEARCH_NAME (psym), + is_static, kind, cu_index); } } } @@ -16974,9 +20340,11 @@ write_one_signatured_type (void **slot, void *d) psymtab->n_static_syms, info->cu_index, 1); - store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->per_cu.offset); + store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, + entry->per_cu.offset.sect_off); obstack_grow (info->types_list, val, 8); - store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->type_offset); + store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, + entry->type_offset_in_tu.cu_off); obstack_grow (info->types_list, val, 8); store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->signature); obstack_grow (info->types_list, val, 8); @@ -16986,6 +20354,35 @@ write_one_signatured_type (void **slot, void *d) return 1; } +/* Recurse into all "included" dependencies and write their symbols as + if they appeared in this psymtab. */ + +static void +recursively_write_psymbols (struct objfile *objfile, + struct partial_symtab *psymtab, + struct mapped_symtab *symtab, + htab_t psyms_seen, + offset_type cu_index) +{ + int i; + + for (i = 0; i < psymtab->number_of_dependencies; ++i) + if (psymtab->dependencies[i]->user != NULL) + recursively_write_psymbols (objfile, psymtab->dependencies[i], + symtab, psyms_seen, cu_index); + + write_psymbols (symtab, + psyms_seen, + objfile->global_psymbols.list + psymtab->globals_offset, + psymtab->n_global_syms, cu_index, + 0); + write_psymbols (symtab, + psyms_seen, + objfile->static_psymbols.list + psymtab->statics_offset, + psymtab->n_static_syms, cu_index, + 1); +} + /* Create an index file for OBJFILE in the directory DIR. */ static void @@ -17000,7 +20397,6 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir) struct mapped_symtab *symtab; offset_type val, size_of_contents, total_len; struct stat st; - char buf[8]; htab_t psyms_seen; htab_t cu_index_htab; struct psymtab_cu_index_map *psymtab_cu_index_map; @@ -17070,16 +20466,8 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir) struct psymtab_cu_index_map *map; void **slot; - write_psymbols (symtab, - psyms_seen, - objfile->global_psymbols.list + psymtab->globals_offset, - psymtab->n_global_syms, i, - 0); - write_psymbols (symtab, - psyms_seen, - objfile->static_psymbols.list + psymtab->statics_offset, - psymtab->n_static_syms, i, - 1); + if (psymtab->user == NULL) + recursively_write_psymbols (objfile, psymtab, symtab, psyms_seen, i); map = &psymtab_cu_index_map[i]; map->psymtab = psymtab; @@ -17089,7 +20477,8 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir) gdb_assert (*slot == NULL); *slot = map; - store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, per_cu->offset); + store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, + per_cu->offset.sect_off); obstack_grow (&cu_list, val, 8); store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, per_cu->length); obstack_grow (&cu_list, val, 8); @@ -17112,6 +20501,10 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir) write_one_signatured_type, &sig_data); } + /* Now that we've processed all symbols we can shrink their cu_indices + lists. */ + uniquify_cu_indices (symtab); + obstack_init (&constant_pool); make_cleanup_obstack_free (&constant_pool); obstack_init (&symtab_obstack); @@ -17124,7 +20517,7 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir) total_len = size_of_contents; /* The version number. */ - val = MAYBE_SWAP (5); + val = MAYBE_SWAP (8); obstack_grow (&contents, &val, sizeof (val)); /* The offset of the CU list from the start of the file. */ @@ -17277,14 +20670,23 @@ conversational style, when possible."), &set_dwarf2_cmdlist, &show_dwarf2_cmdlist); - add_setshow_zinteger_cmd ("dwarf2-die", no_class, &dwarf2_die_debug, _("\ + add_setshow_boolean_cmd ("dwarf2-read", no_class, &dwarf2_read_debug, _("\ +Set debugging of the dwarf2 reader."), _("\ +Show debugging of the dwarf2 reader."), _("\ +When enabled, debugging messages are printed during dwarf2 reading\n\ +and symtab expansion."), + NULL, + NULL, + &setdebuglist, &showdebuglist); + + add_setshow_zuinteger_cmd ("dwarf2-die", no_class, &dwarf2_die_debug, _("\ Set debugging of the dwarf2 DIE reader."), _("\ Show debugging of the dwarf2 DIE reader."), _("\ When enabled (non-zero), DIEs are dumped after they are read in.\n\ The value is the maximum depth to print."), - NULL, - NULL, - &setdebuglist, &showdebuglist); + NULL, + NULL, + &setdebuglist, &showdebuglist); add_setshow_boolean_cmd ("check-physname", no_class, &check_physname, _("\ Set cross-checking of \"physname\" code against demangler."), _("\ @@ -17294,6 +20696,18 @@ the demangler."), NULL, show_check_physname, &setdebuglist, &showdebuglist); + add_setshow_boolean_cmd ("use-deprecated-index-sections", + no_class, &use_deprecated_index_sections, _("\ +Set whether to use deprecated gdb_index sections."), _("\ +Show whether to use deprecated gdb_index sections."), _("\ +When enabled, deprecated .gdb_index sections are used anyway.\n\ +Normally they are ignored either because of a missing feature or\n\ +performance issue.\n\ +Warning: This option must be enabled before gdb reads the file."), + NULL, + NULL, + &setlist, &showlist); + c = add_cmd ("gdb-index", class_files, save_gdb_index_command, _("\ Save a gdb-index file.\n\ diff --git a/contrib/gdb-7/gdb/elfread.c b/contrib/gdb-7/gdb/elfread.c index ca1c2a9d3e..14952b80bc 100644 --- a/contrib/gdb-7/gdb/elfread.c +++ b/contrib/gdb-7/gdb/elfread.c @@ -1,6 +1,6 @@ /* Read ELF (Executable and Linking Format) object files for GDB. - Copyright (C) 1991-2012 Free Software Foundation, Inc. + Copyright (C) 1991-2013 Free Software Foundation, Inc. Written by Fred Fish at Cygnus Support. @@ -36,11 +36,15 @@ #include "demangle.h" #include "psympriv.h" #include "filenames.h" +#include "probe.h" +#include "arch-utils.h" #include "gdbtypes.h" #include "value.h" #include "infcall.h" #include "gdbthread.h" #include "regcache.h" +#include "bcache.h" +#include "gdb_bfd.h" extern void _initialize_elfread (void); @@ -59,6 +63,10 @@ struct elfinfo asection *mdebugsect; /* Section pointer for .mdebug section */ }; +/* Per-objfile data for probe info. */ + +static const struct objfile_data *probe_key = NULL; + static void free_elfinfo (void *); /* Minimal symbols located at the GOT entries for .plt - that is the real @@ -141,7 +149,7 @@ elf_symfile_segments (bfd *abfd) binaries are not relocatable. */ if (bfd_get_section_size (sect) > 0 && j == num_segments && (bfd_get_section_flags (abfd, sect) & SEC_LOAD) != 0) - warning (_("Loadable segment \"%s\" outside of ELF segments"), + warning (_("Loadable section \"%s\" outside of ELF segments"), bfd_section_name (abfd, sect)); } @@ -197,7 +205,7 @@ record_minimal_symbol (const char *name, int name_len, int copy_name, if (ms_type == mst_text || ms_type == mst_file_text || ms_type == mst_text_gnu_ifunc) - address = gdbarch_smash_text_address (gdbarch, address); + address = gdbarch_addr_bits_remove (gdbarch, address); return prim_record_minimal_symbol_full (name, name_len, copy_name, address, ms_type, bfd_section->index, @@ -238,9 +246,9 @@ elf_symtab_read (struct objfile *objfile, int type, seen any section info for it yet. */ asymbol *filesym = 0; /* Name of filesym. This is either a constant string or is saved on - the objfile's obstack. */ - char *filesymname = ""; - struct dbx_symfile_info *dbx = objfile->deprecated_sym_stab_info; + the objfile's filename cache. */ + const char *filesymname = ""; + struct dbx_symfile_info *dbx = DBX_SYMFILE_INFO (objfile); int stripped = (bfd_get_symcount (objfile->obfd) == 0); for (i = 0; i < number_of_symbols; i++) @@ -265,7 +273,7 @@ elf_symtab_read (struct objfile *objfile, int type, offset = ANOFFSET (objfile->section_offsets, sym->section->index); if (type == ST_DYNAMIC - && sym->section == &bfd_und_section + && sym->section == bfd_und_section_ptr && (sym->flags & BSF_FUNCTION)) { struct minimal_symbol *msym; @@ -301,6 +309,23 @@ elf_symtab_read (struct objfile *objfile, int type, if (!sect) continue; + /* On ia64-hpux, we have discovered that the system linker + adds undefined symbols with nonzero addresses that cannot + be right (their address points inside the code of another + function in the .text section). This creates problems + when trying to determine which symbol corresponds to + a given address. + + We try to detect those buggy symbols by checking which + section we think they correspond to. Normally, PLT symbols + are stored inside their own section, and the typical name + for that section is ".plt". So, if there is a ".plt" + section, and yet the section name of our symbol does not + start with ".plt", we ignore that symbol. */ + if (strncmp (sect->name, ".plt", 4) != 0 + && bfd_get_section_by_name (abfd, ".plt") != NULL) + continue; + symaddr += ANOFFSET (objfile->section_offsets, sect->index); msym = record_minimal_symbol @@ -327,13 +352,13 @@ elf_symtab_read (struct objfile *objfile, int type, sectinfo = NULL; } filesym = sym; - filesymname = - obsavestring ((char *) filesym->name, strlen (filesym->name), - &objfile->objfile_obstack); + filesymname = bcache (filesym->name, strlen (filesym->name) + 1, + objfile->per_bfd->filename_cache); } else if (sym->flags & BSF_SECTION_SYM) continue; - else if (sym->flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK)) + else if (sym->flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK + | BSF_GNU_UNIQUE)) { struct minimal_symbol *msym; @@ -344,7 +369,7 @@ elf_symtab_read (struct objfile *objfile, int type, symaddr = sym->value + sym->section->vma; /* Relocate all non-absolute and non-TLS symbols by the section offset. */ - if (sym->section != &bfd_abs_section + if (sym->section != bfd_abs_section_ptr && !(sym->section->flags & SEC_THREAD_LOCAL)) { symaddr += offset; @@ -352,7 +377,7 @@ elf_symtab_read (struct objfile *objfile, int type, /* For non-absolute symbols, use the type of the section they are relative to, to intuit text/data. Bfd provides no way of figuring this out for absolute symbols. */ - if (sym->section == &bfd_abs_section) + if (sym->section == bfd_abs_section_ptr) { /* This is a hack to get the minimal symbol type right for Irix 5, which has absolute addresses @@ -389,7 +414,7 @@ elf_symtab_read (struct objfile *objfile, int type, } else if (sym->section->flags & SEC_CODE) { - if (sym->flags & (BSF_GLOBAL | BSF_WEAK)) + if (sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) { if (sym->flags & BSF_GNU_INDIRECT_FUNCTION) ms_type = mst_text_gnu_ifunc; @@ -419,7 +444,7 @@ elf_symtab_read (struct objfile *objfile, int type, } else if (sym->section->flags & SEC_ALLOC) { - if (sym->flags & (BSF_GLOBAL | BSF_WEAK)) + if (sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) { if (sym->section->flags & SEC_LOAD) { @@ -494,7 +519,7 @@ elf_symtab_read (struct objfile *objfile, int type, symaddr = sym->value + sym->section->vma; /* Relocate non-absolute symbols by the section offset. */ - if (sym->section != &bfd_abs_section) + if (sym->section != bfd_abs_section_ptr) symaddr += offset; sectinfo->sections[special_local_sect] = symaddr; /* The special local symbols don't go in the @@ -532,21 +557,14 @@ elf_symtab_read (struct objfile *objfile, int type, if (msym) { - /* Pass symbol size field in via BFD. FIXME!!! */ - elf_symbol_type *elf_sym; - /* NOTE: uweigand-20071112: A synthetic symbol does not have an - ELF-private part. However, in some cases (e.g. synthetic - 'dot' symbols on ppc64) the udata.p entry is set to point back - to the original ELF symbol it was derived from. Get the size - from that symbol. */ + ELF-private part. */ if (type != ST_SYNTHETIC) - elf_sym = (elf_symbol_type *) sym; - else - elf_sym = (elf_symbol_type *) sym->udata.p; - - if (elf_sym) - MSYMBOL_SIZE(msym) = elf_sym->internal_elf_sym.st_size; + { + /* Pass symbol size field in via BFD. FIXME!!! */ + elf_symbol_type *elf_sym = (elf_symbol_type *) sym; + SET_MSYMBOL_SIZE (msym, elf_sym->internal_elf_sym.st_size); + } msym->filename = filesymname; gdbarch_elf_make_msymbol_special (gdbarch, sym, msym); @@ -570,7 +588,8 @@ elf_symtab_read (struct objfile *objfile, int type, sym->section, objfile); if (mtramp) { - MSYMBOL_SIZE (mtramp) = MSYMBOL_SIZE (msym); + SET_MSYMBOL_SIZE (mtramp, MSYMBOL_SIZE (msym)); + mtramp->created_by_gdb = 1; mtramp->filename = filesymname; gdbarch_elf_make_msymbol_special (gdbarch, sym, mtramp); } @@ -593,7 +612,6 @@ elf_rel_plt_read (struct objfile *objfile, asymbol **dyn_symbol_table) bfd *obfd = objfile->obfd; const struct elf_backend_data *bed = get_elf_backend_data (obfd); asection *plt, *relplt, *got_plt; - unsigned u; int plt_elf_idx; bfd_size_type reloc_count, reloc; char *string_buffer = NULL; @@ -632,7 +650,7 @@ elf_rel_plt_read (struct objfile *objfile, asymbol **dyn_symbol_table) reloc_count = relplt->size / elf_section_data (relplt)->this_hdr.sh_entsize; for (reloc = 0; reloc < reloc_count; reloc++) { - const char *name, *name_got_plt; + const char *name; struct minimal_symbol *msym; CORE_ADDR address; const size_t got_suffix_len = strlen (SYMBOL_GOT_PLT_SUFFIX); @@ -665,7 +683,7 @@ elf_rel_plt_read (struct objfile *objfile, asymbol **dyn_symbol_table) 1, address, mst_slot_got_plt, got_plt, objfile); if (msym) - MSYMBOL_SIZE (msym) = ptr_size; + SET_MSYMBOL_SIZE (msym, ptr_size); } do_cleanups (back_to); @@ -903,7 +921,7 @@ elf_gnu_ifunc_resolve_name (const char *name, CORE_ADDR *addr_p) static CORE_ADDR elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc) { - char *name_at_pc; + const char *name_at_pc; CORE_ADDR start_at_pc, address; struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func; struct value *function, *address_val; @@ -978,6 +996,9 @@ elf_gnu_ifunc_resolver_stop (struct breakpoint *b) prev_frame_id, bp_gnu_ifunc_resolver_return); + /* set_momentary_breakpoint invalidates PREV_FRAME. */ + prev_frame = NULL; + /* Add new b_return to the ring list b->related_breakpoint. */ gdb_assert (b_return->related_breakpoint == b_return); b_return->related_breakpoint = b->related_breakpoint; @@ -994,6 +1015,7 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b) struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func; struct type *value_type = TYPE_TARGET_TYPE (func_func_type); struct regcache *regcache = get_thread_regcache (inferior_ptid); + struct value *func_func; struct value *value; CORE_ADDR resolved_address, resolved_pc; struct symtab_and_line sal; @@ -1001,14 +1023,6 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b) gdb_assert (b->type == bp_gnu_ifunc_resolver_return); - value = allocate_value (value_type); - gdbarch_return_value (gdbarch, func_func_type, value_type, regcache, - value_contents_raw (value), NULL); - resolved_address = value_as_address (value); - resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch, - resolved_address, - ¤t_target); - while (b->related_breakpoint != b) { struct breakpoint *b_next = b->related_breakpoint; @@ -1029,6 +1043,18 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b) b = b_next; } gdb_assert (b->type == bp_gnu_ifunc_resolver); + gdb_assert (b->loc->next == NULL); + + func_func = allocate_value (func_func_type); + set_value_address (func_func, b->loc->related_address); + + value = allocate_value (value_type); + gdbarch_return_value (gdbarch, func_func, value_type, regcache, + value_contents_raw (value), NULL); + resolved_address = value_as_address (value); + resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch, + resolved_address, + ¤t_target); gdb_assert (current_program_space == b->pspace || b->pspace == NULL); elf_gnu_ifunc_record_cache (b->addr_string, resolved_pc); @@ -1042,42 +1068,30 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b) update_breakpoint_locations (b, sals, sals_end); } -struct build_id - { - size_t size; - gdb_byte data[1]; - }; - /* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ -static struct build_id * +static const struct elf_build_id * build_id_bfd_get (bfd *abfd) { - struct build_id *retval; - if (!bfd_check_format (abfd, bfd_object) || bfd_get_flavour (abfd) != bfd_target_elf_flavour || elf_tdata (abfd)->build_id == NULL) return NULL; - retval = xmalloc (sizeof *retval - 1 + elf_tdata (abfd)->build_id_size); - retval->size = elf_tdata (abfd)->build_id_size; - memcpy (retval->data, elf_tdata (abfd)->build_id, retval->size); - - return retval; + return elf_tdata (abfd)->build_id; } /* Return if FILENAME has NT_GNU_BUILD_ID matching the CHECK value. */ static int -build_id_verify (const char *filename, struct build_id *check) +build_id_verify (const char *filename, const struct elf_build_id *check) { bfd *abfd; - struct build_id *found = NULL; + const struct elf_build_id *found; int retval = 0; /* We expect to be silent on the non-existing files. */ - abfd = bfd_open_maybe_remote (filename); + abfd = gdb_bfd_open_maybe_remote (filename); if (abfd == NULL) return 0; @@ -1092,17 +1106,18 @@ build_id_verify (const char *filename, struct build_id *check) else retval = 1; - gdb_bfd_close_or_warn (abfd); - - xfree (found); + gdb_bfd_unref (abfd); return retval; } static char * -build_id_to_debug_filename (struct build_id *build_id) +build_id_to_debug_filename (const struct elf_build_id *build_id) { char *link, *debugdir, *retval = NULL; + VEC (char_ptr) *debugdir_vec; + struct cleanup *back_to; + int ix; /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ link = alloca (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 @@ -1111,22 +1126,18 @@ build_id_to_debug_filename (struct build_id *build_id) /* Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will cause "/.build-id/..." lookups. */ - debugdir = debug_file_directory; - do + debugdir_vec = dirnames_to_char_ptr_vec (debug_file_directory); + back_to = make_cleanup_free_char_ptr_vec (debugdir_vec); + + for (ix = 0; VEC_iterate (char_ptr, debugdir_vec, ix, debugdir); ++ix) { - char *s, *debugdir_end; - gdb_byte *data = build_id->data; + size_t debugdir_len = strlen (debugdir); + const gdb_byte *data = build_id->data; size_t size = build_id->size; + char *s; - while (*debugdir == DIRNAME_SEPARATOR) - debugdir++; - - debugdir_end = strchr (debugdir, DIRNAME_SEPARATOR); - if (debugdir_end == NULL) - debugdir_end = &debugdir[strlen (debugdir)]; - - memcpy (link, debugdir, debugdir_end - debugdir); - s = &link[debugdir_end - debugdir]; + memcpy (link, debugdir, debugdir_len); + s = &link[debugdir_len]; s += sprintf (s, "/.build-id/"); if (size > 0) { @@ -1151,18 +1162,16 @@ build_id_to_debug_filename (struct build_id *build_id) if (retval != NULL) break; - - debugdir = debugdir_end; } - while (*debugdir != 0); + do_cleanups (back_to); return retval; } static char * find_separate_debug_file_by_buildid (struct objfile *objfile) { - struct build_id *build_id; + const struct elf_build_id *build_id; build_id = build_id_bfd_get (objfile->obfd); if (build_id != NULL) @@ -1170,7 +1179,6 @@ find_separate_debug_file_by_buildid (struct objfile *objfile) char *build_id_name; build_id_name = build_id_to_debug_filename (build_id); - xfree (build_id); /* Prevent looping on a stripped .debug file. */ if (build_id_name != NULL && filename_cmp (build_id_name, objfile->name) == 0) @@ -1222,6 +1230,14 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) long symcount = 0, dynsymcount = 0, synthcount, storage_needed; asymbol **symbol_table = NULL, **dyn_symbol_table = NULL; asymbol *synthsyms; + struct dbx_symfile_info *dbx; + + if (symtab_create_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Reading minimal symbols of objfile %s ...\n", + objfile->name); + } init_minimal_symbol_collection (); back_to = make_cleanup_discard_minimal_symbols (); @@ -1229,16 +1245,13 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) memset ((char *) &ei, 0, sizeof (ei)); /* Allocate struct to keep track of the symfile. */ - objfile->deprecated_sym_stab_info = (struct dbx_symfile_info *) - xmalloc (sizeof (struct dbx_symfile_info)); - memset ((char *) objfile->deprecated_sym_stab_info, - 0, sizeof (struct dbx_symfile_info)); + dbx = XCNEW (struct dbx_symfile_info); + set_objfile_data (objfile, dbx_objfile_data_key, dbx); make_cleanup (free_elfinfo, (void *) objfile); /* Process the normal ELF symbol table first. This may write some - chain of info into the dbx_symfile_info in - objfile->deprecated_sym_stab_info, which can later be used by - elfstab_offset_sections. */ + chain of info into the dbx_symfile_info of the objfile, which can + later be used by elfstab_offset_sections. */ storage_needed = bfd_get_symtab_upper_bound (objfile->obfd); if (storage_needed < 0) @@ -1376,6 +1389,9 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) bfd_section_size (abfd, str_sect)); } + if (symtab_create_debug) + fprintf_unfiltered (gdb_stdlog, "Done reading minimal symbols.\n"); + if (dwarf2_has_info (objfile, NULL)) { /* elf_sym_fns_gdb_index cannot handle simultaneous non-DWARF debug @@ -1397,8 +1413,18 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) /* 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'. */ - else if (!objfile_has_partial_symbols (objfile)) + `.note.gnu.build-id'. + + .gnu_debugdata is !objfile_has_partial_symbols because it contains only + .symtab, not .debug_* section. But if we already added .gnu_debugdata as + an objfile via find_separate_debug_file_in_section there was no separate + debug info available. Therefore do not attempt to search for another one, + objfile->separate_debug_objfile->separate_debug_objfile GDB guarantees to + be NULL and we would possibly violate it. */ + + else if (!objfile_has_partial_symbols (objfile) + && objfile->separate_debug_objfile == NULL + && objfile->separate_debug_objfile_backlink == NULL) { char *debugfile; @@ -1409,10 +1435,12 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) if (debugfile) { + struct cleanup *cleanup = make_cleanup (xfree, debugfile); bfd *abfd = symfile_bfd_open (debugfile); + make_cleanup_bfd_unref (abfd); symbol_file_add_separate (abfd, symfile_flags, objfile); - xfree (debugfile); + do_cleanups (cleanup); } } } @@ -1426,15 +1454,14 @@ read_psyms (struct objfile *objfile) dwarf2_build_psymtabs (objfile); } -/* This cleans up the objfile's deprecated_sym_stab_info pointer, and - the chain of stab_section_info's, that might be dangling from - it. */ +/* This cleans up the objfile's dbx symfile info, and the chain of + stab_section_info's, that might be dangling from it. */ static void free_elfinfo (void *objp) { struct objfile *objfile = (struct objfile *) objp; - struct dbx_symfile_info *dbxinfo = objfile->deprecated_sym_stab_info; + struct dbx_symfile_info *dbxinfo = DBX_SYMFILE_INFO (objfile); struct stab_section_info *ssi, *nssi; ssi = dbxinfo->stab_section_info; @@ -1471,11 +1498,6 @@ elf_new_init (struct objfile *ignore) static void elf_symfile_finish (struct objfile *objfile) { - if (objfile->deprecated_sym_stab_info != NULL) - { - xfree (objfile->deprecated_sym_stab_info); - } - dwarf2_free_objfile (objfile); } @@ -1509,7 +1531,7 @@ void elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst) { const char *filename = pst->filename; - struct dbx_symfile_info *dbx = objfile->deprecated_sym_stab_info; + struct dbx_symfile_info *dbx = DBX_SYMFILE_INFO (objfile); struct stab_section_info *maybe = dbx->stab_section_info; struct stab_section_info *questionable = 0; int i; @@ -1559,7 +1581,113 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst) complaint (&symfile_complaints, _("elf/stab section information missing for %s"), filename); } + +/* Implementation of `sym_get_probes', as documented in symfile.h. */ + +static VEC (probe_p) * +elf_get_probes (struct objfile *objfile) +{ + VEC (probe_p) *probes_per_objfile; + + /* Have we parsed this objfile's probes already? */ + probes_per_objfile = objfile_data (objfile, probe_key); + + if (!probes_per_objfile) + { + int ix; + const struct probe_ops *probe_ops; + + /* Here we try to gather information about all types of probes from the + objfile. */ + for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, probe_ops); + ix++) + probe_ops->get_probes (&probes_per_objfile, objfile); + + if (probes_per_objfile == NULL) + { + VEC_reserve (probe_p, probes_per_objfile, 1); + gdb_assert (probes_per_objfile != NULL); + } + + set_objfile_data (objfile, probe_key, probes_per_objfile); + } + + return probes_per_objfile; +} + +/* Implementation of `sym_get_probe_argument_count', as documented in + symfile.h. */ + +static unsigned +elf_get_probe_argument_count (struct probe *probe) +{ + return probe->pops->get_probe_argument_count (probe); +} + +/* Implementation of `sym_evaluate_probe_argument', as documented in + symfile.h. */ + +static struct value * +elf_evaluate_probe_argument (struct probe *probe, unsigned n) +{ + return probe->pops->evaluate_probe_argument (probe, n); +} + +/* Implementation of `sym_compile_to_ax', as documented in symfile.h. */ + +static void +elf_compile_to_ax (struct probe *probe, + struct agent_expr *expr, + struct axs_value *value, + unsigned n) +{ + probe->pops->compile_to_ax (probe, expr, value, n); +} + +/* Implementation of `sym_relocate_probe', as documented in symfile.h. */ + +static void +elf_symfile_relocate_probe (struct objfile *objfile, + struct section_offsets *new_offsets, + struct section_offsets *delta) +{ + int ix; + VEC (probe_p) *probes = objfile_data (objfile, probe_key); + struct probe *probe; + + for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++) + probe->pops->relocate (probe, ANOFFSET (delta, SECT_OFF_TEXT (objfile))); +} + +/* Helper function used to free the space allocated for storing SystemTap + probe information. */ + +static void +probe_key_free (struct objfile *objfile, void *d) +{ + int ix; + VEC (probe_p) *probes = d; + struct probe *probe; + + for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++) + probe->pops->destroy (probe); + + VEC_free (probe_p, probes); +} + + +/* Implementation `sym_probe_fns', as documented in symfile.h. */ + +static const struct sym_probe_fns elf_probe_fns = +{ + elf_get_probes, /* sym_get_probes */ + elf_get_probe_argument_count, /* sym_get_probe_argument_count */ + elf_evaluate_probe_argument, /* sym_evaluate_probe_argument */ + elf_compile_to_ax, /* sym_compile_to_ax */ + elf_symfile_relocate_probe, /* sym_relocate_probe */ +}; + /* Register that we are able to handle ELF object file formats. */ static const struct sym_fns elf_sym_fns = @@ -1574,6 +1702,7 @@ static const struct sym_fns elf_sym_fns = elf_symfile_segments, /* Get segment information from a file. */ NULL, default_symfile_relocate, /* Relocate a debug section. */ + &elf_probe_fns, /* sym_probe_fns */ &psym_functions }; @@ -1592,6 +1721,7 @@ static const struct sym_fns elf_sym_fns_lazy_psyms = elf_symfile_segments, /* Get segment information from a file. */ NULL, default_symfile_relocate, /* Relocate a debug section. */ + &elf_probe_fns, /* sym_probe_fns */ &psym_functions }; @@ -1609,6 +1739,7 @@ static const struct sym_fns elf_sym_fns_gdb_index = elf_symfile_segments, /* Get segment information from a file. */ NULL, default_symfile_relocate, /* Relocate a debug section. */ + &elf_probe_fns, /* sym_probe_fns */ &dwarf2_gdb_index_functions }; @@ -1625,6 +1756,7 @@ static const struct gnu_ifunc_fns elf_gnu_ifunc_fns = void _initialize_elfread (void) { + probe_key = register_objfile_data_with_cleanup (NULL, probe_key_free); add_symtab_fns (&elf_sym_fns); elf_objfile_gnu_ifunc_cache_data = register_objfile_data (); diff --git a/contrib/gdb-7/gdb/environ.c b/contrib/gdb-7/gdb/environ.c index 33426eb90b..50653dafdc 100644 --- a/contrib/gdb-7/gdb/environ.c +++ b/contrib/gdb-7/gdb/environ.c @@ -1,7 +1,6 @@ /* environ.c -- library for manipulating environments for GNU. - Copyright (C) 1986, 1989-1995, 2000, 2003, 2005, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 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 diff --git a/contrib/gdb-7/gdb/environ.h b/contrib/gdb-7/gdb/environ.h index 52d51ef7c8..876a9c3d6d 100644 --- a/contrib/gdb-7/gdb/environ.h +++ b/contrib/gdb-7/gdb/environ.h @@ -1,6 +1,5 @@ /* Header for environment manipulation library. - Copyright (C) 1989, 1992, 2000, 2005, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1989-2013 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 diff --git a/contrib/gdb-7/gdb/eval.c b/contrib/gdb-7/gdb/eval.c index d48b450e92..58c9e15a57 100644 --- a/contrib/gdb-7/gdb/eval.c +++ b/contrib/gdb-7/gdb/eval.c @@ -1,6 +1,6 @@ /* Evaluate expressions for GDB. - Copyright (C) 1986-2003, 2005-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -41,7 +41,6 @@ #include "gdb_obstack.h" #include "objfiles.h" #include "python/python.h" -#include "wrapper.h" #include "gdb_assert.h" @@ -57,8 +56,6 @@ static struct value *evaluate_subexp_for_sizeof (struct expression *, int *); static struct value *evaluate_subexp_for_address (struct expression *, int *, enum noside); -static char *get_label (struct expression *, int *); - static struct value *evaluate_struct_tuple (struct value *, struct expression *, int *, enum noside, int); @@ -79,7 +76,7 @@ evaluate_subexp (struct type *expect_type, struct expression *exp, and return the result as a number. */ CORE_ADDR -parse_and_eval_address (char *exp) +parse_and_eval_address (const char *exp) { struct expression *expr = parse_expression (exp); CORE_ADDR addr; @@ -107,7 +104,7 @@ parse_and_eval_long (char *exp) } struct value * -parse_and_eval (char *exp) +parse_and_eval (const char *exp) { struct expression *expr = parse_expression (exp); struct value *val; @@ -124,9 +121,9 @@ parse_and_eval (char *exp) EXPP is advanced to point to the comma. */ struct value * -parse_to_comma_and_eval (char **expp) +parse_to_comma_and_eval (const char **expp) { - struct expression *expr = parse_exp_1 (expp, (struct block *) 0, 1); + struct expression *expr = parse_exp_1 (expp, 0, (struct block *) 0, 1); struct value *val; struct cleanup *old_chain = make_cleanup (free_current_contents, &expr); @@ -234,9 +231,21 @@ fetch_subexp_value (struct expression *exp, int *pc, struct value **valp, /* Make sure it's not lazy, so that after the target stops again we have a non-lazy previous value to compare with. */ - if (result != NULL - && (!value_lazy (result) || gdb_value_fetch_lazy (result))) - *valp = result; + if (result != NULL) + { + if (!value_lazy (result)) + *valp = result; + else + { + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ERROR) + { + value_fetch_lazy (result); + *valp = result; + } + } + } if (val_chain) { @@ -269,27 +278,8 @@ extract_field_op (struct expression *exp, int *subexp) return result; } -/* If the next expression is an OP_LABELED, skips past it, - returning the label. Otherwise, does nothing and returns NULL. */ - -static char * -get_label (struct expression *exp, int *pos) -{ - if (exp->elts[*pos].opcode == OP_LABELED) - { - int pc = (*pos)++; - char *name = &exp->elts[pc + 2].string; - int tem = longest_to_int (exp->elts[pc + 1].longconst); - - (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); - return name; - } - else - return NULL; -} - -/* This function evaluates tuples (in (the deleted) Chill) or - brace-initializers (in C/C++) for structure types. */ +/* This function evaluates brace-initializers (in C/C++) for + structure types. */ static struct value * evaluate_struct_tuple (struct value *struct_val, @@ -297,141 +287,57 @@ evaluate_struct_tuple (struct value *struct_val, int *pos, enum noside noside, int nargs) { struct type *struct_type = check_typedef (value_type (struct_val)); - struct type *substruct_type = struct_type; struct type *field_type; int fieldno = -1; - int variantno = -1; - int subfieldno = -1; while (--nargs >= 0) { - int pc = *pos; struct value *val = NULL; - int nlabels = 0; int bitpos, bitsize; bfd_byte *addr; - /* Skip past the labels, and count them. */ - while (get_label (exp, pos) != NULL) - nlabels++; - - do - { - char *label = get_label (exp, &pc); - - if (label) - { - for (fieldno = 0; fieldno < TYPE_NFIELDS (struct_type); - fieldno++) - { - char *field_name = TYPE_FIELD_NAME (struct_type, fieldno); - - if (field_name != NULL && strcmp (field_name, label) == 0) - { - variantno = -1; - subfieldno = fieldno; - substruct_type = struct_type; - goto found; - } - } - for (fieldno = 0; fieldno < TYPE_NFIELDS (struct_type); - fieldno++) - { - char *field_name = TYPE_FIELD_NAME (struct_type, fieldno); - - field_type = TYPE_FIELD_TYPE (struct_type, fieldno); - if ((field_name == 0 || *field_name == '\0') - && TYPE_CODE (field_type) == TYPE_CODE_UNION) - { - variantno = 0; - for (; variantno < TYPE_NFIELDS (field_type); - variantno++) - { - substruct_type - = TYPE_FIELD_TYPE (field_type, variantno); - if (TYPE_CODE (substruct_type) == TYPE_CODE_STRUCT) - { - for (subfieldno = 0; - subfieldno < TYPE_NFIELDS (substruct_type); - subfieldno++) - { - if (strcmp(TYPE_FIELD_NAME (substruct_type, - subfieldno), - label) == 0) - { - goto found; - } - } - } - } - } - } - error (_("there is no field named %s"), label); - found: - ; - } - else - { - /* Unlabelled tuple element - go to next field. */ - if (variantno >= 0) - { - subfieldno++; - if (subfieldno >= TYPE_NFIELDS (substruct_type)) - { - variantno = -1; - substruct_type = struct_type; - } - } - if (variantno < 0) - { - fieldno++; - /* Skip static fields. */ - while (fieldno < TYPE_NFIELDS (struct_type) - && field_is_static (&TYPE_FIELD (struct_type, - fieldno))) - fieldno++; - subfieldno = fieldno; - if (fieldno >= TYPE_NFIELDS (struct_type)) - error (_("too many initializers")); - field_type = TYPE_FIELD_TYPE (struct_type, fieldno); - if (TYPE_CODE (field_type) == TYPE_CODE_UNION - && TYPE_FIELD_NAME (struct_type, fieldno)[0] == '0') - error (_("don't know which variant you want to set")); - } - } + fieldno++; + /* Skip static fields. */ + while (fieldno < TYPE_NFIELDS (struct_type) + && field_is_static (&TYPE_FIELD (struct_type, + fieldno))) + fieldno++; + if (fieldno >= TYPE_NFIELDS (struct_type)) + error (_("too many initializers")); + field_type = TYPE_FIELD_TYPE (struct_type, fieldno); + if (TYPE_CODE (field_type) == TYPE_CODE_UNION + && TYPE_FIELD_NAME (struct_type, fieldno)[0] == '0') + error (_("don't know which variant you want to set")); + + /* Here, struct_type is the type of the inner struct, + while substruct_type is the type of the inner struct. + These are the same for normal structures, but a variant struct + contains anonymous union fields that contain substruct fields. + The value fieldno is the index of the top-level (normal or + anonymous union) field in struct_field, while the value + subfieldno is the index of the actual real (named inner) field + in substruct_type. */ + + field_type = TYPE_FIELD_TYPE (struct_type, fieldno); + if (val == 0) + val = evaluate_subexp (field_type, exp, pos, noside); + + /* Now actually set the field in struct_val. */ + + /* Assign val to field fieldno. */ + if (value_type (val) != field_type) + val = value_cast (field_type, val); + + bitsize = TYPE_FIELD_BITSIZE (struct_type, fieldno); + bitpos = TYPE_FIELD_BITPOS (struct_type, fieldno); + addr = value_contents_writeable (struct_val) + bitpos / 8; + if (bitsize) + modify_field (struct_type, addr, + value_as_long (val), bitpos % 8, bitsize); + else + memcpy (addr, value_contents (val), + TYPE_LENGTH (value_type (val))); - /* Here, struct_type is the type of the inner struct, - while substruct_type is the type of the inner struct. - These are the same for normal structures, but a variant struct - contains anonymous union fields that contain substruct fields. - The value fieldno is the index of the top-level (normal or - anonymous union) field in struct_field, while the value - subfieldno is the index of the actual real (named inner) field - in substruct_type. */ - - field_type = TYPE_FIELD_TYPE (substruct_type, subfieldno); - if (val == 0) - val = evaluate_subexp (field_type, exp, pos, noside); - - /* Now actually set the field in struct_val. */ - - /* Assign val to field fieldno. */ - if (value_type (val) != field_type) - val = value_cast (field_type, val); - - bitsize = TYPE_FIELD_BITSIZE (substruct_type, subfieldno); - bitpos = TYPE_FIELD_BITPOS (struct_type, fieldno); - if (variantno >= 0) - bitpos += TYPE_FIELD_BITPOS (substruct_type, subfieldno); - addr = value_contents_writeable (struct_val) + bitpos / 8; - if (bitsize) - modify_field (struct_type, addr, - value_as_long (val), bitpos % 8, bitsize); - else - memcpy (addr, value_contents (val), - TYPE_LENGTH (value_type (val))); - } - while (--nlabels > 0); } return struct_val; } @@ -756,6 +662,23 @@ make_params (int num_types, struct type **param_types) TYPE_CODE (type) = TYPE_CODE_METHOD; TYPE_VPTR_FIELDNO (type) = -1; TYPE_CHAIN (type) = type; + if (num_types > 0) + { + if (param_types[num_types - 1] == NULL) + { + --num_types; + TYPE_VARARGS (type) = 1; + } + else if (TYPE_CODE (check_typedef (param_types[num_types - 1])) + == TYPE_CODE_VOID) + { + --num_types; + /* Caller should have ensured this. */ + gdb_assert (num_types == 0); + TYPE_PROTOTYPED (type) = 1; + } + } + TYPE_NFIELDS (type) = num_types; TYPE_FIELDS (type) = (struct field *) TYPE_ZALLOC (type, sizeof (struct field) * num_types); @@ -780,7 +703,6 @@ evaluate_subexp_standard (struct type *expect_type, struct type *type; int nargs; struct value **argvec; - int upper, lower; int code; int ix; long mem_offset; @@ -940,16 +862,6 @@ evaluate_subexp_standard (struct type *expect_type, } return value_nsstring (exp->gdbarch, &exp->elts[pc + 2].string, tem + 1); - case OP_BITSTRING: - tem = longest_to_int (exp->elts[pc + 1].longconst); - (*pos) - += 3 + BYTES_TO_EXP_ELEM ((tem + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT); - if (noside == EVAL_SKIP) - goto nosideret; - return value_bitstring (&exp->elts[pc + 2].string, tem, - builtin_type (exp->gdbarch)->builtin_int); - break; - case OP_ARRAY: (*pos) += 3; tem2 = longest_to_int (exp->elts[pc + 1].longconst); @@ -1120,17 +1032,6 @@ evaluate_subexp_standard (struct type *expect_type, return value_slice (array, lowbound, upper - lowbound + 1); } - case TERNOP_SLICE_COUNT: - { - struct value *array = evaluate_subexp (NULL_TYPE, exp, pos, noside); - int lowbound - = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); - int length - = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); - - return value_slice (array, lowbound, length); - } - case TERNOP_COND: /* Skip third and second args to evaluate the first one. */ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); @@ -1345,8 +1246,7 @@ evaluate_subexp_standard (struct type *expect_type, val_type = expect_type; } - struct_return = using_struct_return (exp->gdbarch, - value_type (method), + struct_return = using_struct_return (exp->gdbarch, method, val_type); } else if (expect_type != NULL) @@ -1464,7 +1364,6 @@ evaluate_subexp_standard (struct type *expect_type, alloca (sizeof (struct value *) * (nargs + 3)); if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) { - nargs++; /* First, evaluate the structure into arg2. */ pc2 = (*pos)++; @@ -1488,22 +1387,39 @@ 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")); + type = check_typedef (value_type (arg1)); + if (TYPE_CODE (type) == 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); - if (noside == EVAL_AVOID_SIDE_EFFECTS) + /* Now, say which argument to start evaluating from. */ + nargs++; + tem = 2; + argvec[1] = arg2; + } + else if (TYPE_CODE (type) == TYPE_CODE_MEMBERPTR) { - struct type *method_type = check_typedef (value_type (arg1)); + struct type *type_ptr + = lookup_pointer_type (TYPE_DOMAIN_TYPE (type)); + struct type *target_type_ptr + = lookup_pointer_type (TYPE_TARGET_TYPE (type)); - arg1 = value_zero (method_type, not_lval); + /* Now, convert these values to an address. */ + arg2 = value_cast (type_ptr, arg2); + + mem_offset = value_as_long (arg1); + + arg1 = value_from_pointer (target_type_ptr, + value_as_long (arg2) + mem_offset); + arg1 = value_ind (arg1); + tem = 1; } else - arg1 = cplus_method_ptr_to_value (&arg2, arg1); - - /* Now, say which argument to start evaluating from. */ - tem = 2; + error (_("Non-pointer-to-member value used in pointer-to-member " + "construct")); } else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) { @@ -1674,7 +1590,6 @@ evaluate_subexp_standard (struct type *expect_type, find_overload_match (&argvec[1], nargs, func_name, NON_METHOD, /* not method */ - 0, /* strict match */ NULL, NULL, /* pass NULL symbol since symbol is unknown */ NULL, &symp, NULL, 0); @@ -1710,7 +1625,6 @@ evaluate_subexp_standard (struct type *expect_type, (void) find_overload_match (&argvec[1], nargs, tstr, METHOD, /* method */ - 0, /* strict match */ &arg2, /* the object */ NULL, &valp, NULL, &static_memfuncp, 0); @@ -1754,7 +1668,7 @@ evaluate_subexp_standard (struct type *expect_type, } else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) { - argvec[1] = arg2; + /* Pointer to member. argvec[1] is already set up. */ argvec[0] = arg1; } else if (op == OP_VAR_VALUE || (op == OP_SCOPE && function != NULL)) @@ -1782,7 +1696,6 @@ evaluate_subexp_standard (struct type *expect_type, (void) find_overload_match (&argvec[1], nargs, NULL, /* no need for name */ NON_METHOD, /* not method */ - 0, /* strict match */ NULL, function, /* the function */ NULL, &symp, NULL, no_adl); @@ -1988,16 +1901,10 @@ evaluate_subexp_standard (struct type *expect_type, if (opts.objectprint && TYPE_TARGET_TYPE(type) && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS)) { - real_type = value_rtti_target_type (arg1, &full, &top, &using_enc); + real_type = value_rtti_indirect_type (arg1, &full, &top, + &using_enc); if (real_type) - { - if (TYPE_CODE (type) == TYPE_CODE_PTR) - real_type = lookup_pointer_type (real_type); - else - real_type = lookup_reference_type (real_type); - arg1 = value_cast (real_type, arg1); - } } } @@ -2041,8 +1948,8 @@ evaluate_subexp_standard (struct type *expect_type, case TYPE_CODE_MEMBERPTR: /* Now, convert these values to an address. */ - arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), - arg1); + arg1 = value_cast_pointers (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), + arg1, 1); mem_offset = value_as_long (arg2); @@ -2321,12 +2228,6 @@ evaluate_subexp_standard (struct type *expect_type, arg1 = value_subscript (arg1, value_as_long (arg2)); break; - case TYPE_CODE_BITSTRING: - type = language_bool_type (exp->language_defn, exp->gdbarch); - arg1 = value_bitstring_subscript (type, arg1, - value_as_long (arg2)); - break; - default: if (TYPE_NAME (type)) error (_("cannot subscript something of type `%s'"), @@ -2374,8 +2275,8 @@ evaluate_subexp_standard (struct type *expect_type, struct type *array_type = check_typedef (value_type (array)); LONGEST index = subscript_array[i - 1]; - lower = f77_get_lowerbound (array_type); - array = value_subscripted_rvalue (array, index, lower); + array = value_subscripted_rvalue (array, index, + f77_get_lowerbound (array_type)); } return array; @@ -2684,17 +2585,27 @@ evaluate_subexp_standard (struct type *expect_type, arg1 = value_cast (type, arg1); return arg1; + case UNOP_CAST_TYPE: + arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + type = value_type (arg1); + arg1 = evaluate_subexp (type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (type != value_type (arg1)) + arg1 = value_cast (type, arg1); + return arg1; + case UNOP_DYNAMIC_CAST: - (*pos) += 2; - type = exp->elts[pc + 1].type; + arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + type = value_type (arg1); arg1 = evaluate_subexp (type, exp, pos, noside); if (noside == EVAL_SKIP) goto nosideret; return value_dynamic_cast (type, arg1); case UNOP_REINTERPRET_CAST: - (*pos) += 2; - type = exp->elts[pc + 1].type; + arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + type = value_type (arg1); arg1 = evaluate_subexp (type, exp, pos, noside); if (noside == EVAL_SKIP) goto nosideret; @@ -2711,6 +2622,17 @@ evaluate_subexp_standard (struct type *expect_type, return value_at_lazy (exp->elts[pc + 1].type, value_as_address (arg1)); + case UNOP_MEMVAL_TYPE: + arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + type = value_type (arg1); + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (type, lval_memory); + else + return value_at_lazy (type, value_as_address (arg1)); + case UNOP_MEMVAL_TLS: (*pos) += 3; arg1 = evaluate_subexp (expect_type, exp, pos, noside); @@ -2855,6 +2777,45 @@ evaluate_subexp_standard (struct type *expect_type, else error (_("Attempt to use a type name as an expression")); + case OP_TYPEOF: + case OP_DECLTYPE: + if (noside == EVAL_SKIP) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + goto nosideret; + } + else if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + enum exp_opcode sub_op = exp->elts[*pos].opcode; + struct value *result; + + result = evaluate_subexp (NULL_TYPE, exp, pos, + EVAL_AVOID_SIDE_EFFECTS); + + /* 'decltype' has special semantics for lvalues. */ + if (op == OP_DECLTYPE + && (sub_op == BINOP_SUBSCRIPT + || sub_op == STRUCTOP_MEMBER + || sub_op == STRUCTOP_MPTR + || sub_op == UNOP_IND + || sub_op == STRUCTOP_STRUCT + || sub_op == STRUCTOP_PTR + || sub_op == OP_SCOPE)) + { + struct type *type = value_type (result); + + if (TYPE_CODE (check_typedef (type)) != TYPE_CODE_REF) + { + type = lookup_reference_type (type); + result = allocate_value (type); + } + } + + return result; + } + else + error (_("Attempt to use a type as an expression")); + default: /* Removing this case and compiling with gcc -Wall reveals that a lot of cases are hitting this case. Some of these should @@ -2913,6 +2874,17 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, return value_cast (lookup_pointer_type (exp->elts[pc + 1].type), evaluate_subexp (NULL_TYPE, exp, pos, noside)); + case UNOP_MEMVAL_TYPE: + { + struct type *type; + + (*pos) += 1; + x = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + type = value_type (x); + return value_cast (lookup_pointer_type (type), + evaluate_subexp (NULL_TYPE, exp, pos, noside)); + } + case OP_VAR_VALUE: var = exp->elts[pc + 2].symbol; @@ -2957,12 +2929,12 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, { struct type *type = check_typedef (value_type (x)); - if (VALUE_LVAL (x) == lval_memory || value_must_coerce_to_target (x)) - return value_zero (lookup_pointer_type (value_type (x)), - not_lval); - else if (TYPE_CODE (type) == TYPE_CODE_REF) + if (TYPE_CODE (type) == TYPE_CODE_REF) return value_zero (lookup_pointer_type (TYPE_TARGET_TYPE (type)), not_lval); + else if (VALUE_LVAL (x) == lval_memory || value_must_coerce_to_target (x)) + return value_zero (lookup_pointer_type (value_type (x)), + not_lval); else error (_("Attempt to take address of " "value not located in memory.")); @@ -3055,6 +3027,12 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos) type = check_typedef (exp->elts[pc + 1].type); return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); + case UNOP_MEMVAL_TYPE: + (*pos) += 1; + val = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + type = check_typedef (value_type (val)); + return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); + case OP_VAR_VALUE: (*pos) += 4; type = check_typedef (SYMBOL_TYPE (exp->elts[pc + 2].symbol)); diff --git a/contrib/gdb-7/gdb/event-loop.c b/contrib/gdb-7/gdb/event-loop.c index 279335a192..f34f15345e 100644 --- a/contrib/gdb-7/gdb/event-loop.c +++ b/contrib/gdb-7/gdb/event-loop.c @@ -1,5 +1,5 @@ /* Event loop machinery for GDB, the GNU debugger. - Copyright (C) 1999-2002, 2005-2012 Free Software Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. Written by Elena Zannoni of Cygnus Solutions. This file is part of GDB. @@ -20,6 +20,7 @@ #include "defs.h" #include "event-loop.h" #include "event-top.h" +#include "queue.h" #ifdef HAVE_POLL #if defined (HAVE_POLL_H) @@ -68,17 +69,14 @@ typedef void (event_handler_func) (event_data); case of async signal handlers, it is invoke_async_signal_handler. */ -struct gdb_event +typedef struct gdb_event { /* Procedure to call to service this event. */ event_handler_func *proc; /* Data to pass to the event handler. */ event_data data; - - /* Next in list of events or NULL. */ - struct gdb_event *next_event; - }; + } *gdb_event_p; /* Information about each file descriptor we register with the event loop. */ @@ -140,26 +138,9 @@ typedef struct async_event_handler } async_event_handler; - -/* Event queue: - - the first event in the queue is the head of the queue. - It will be the next to be serviced. - - the last event in the queue - - Events can be inserted at the front of the queue or at the end of - the queue. Events will be extracted from the queue for processing - starting from the head. Therefore, events inserted at the head of - the queue will be processed in a last in first out fashion, while - those inserted at the tail of the queue will be processed in a first - in first out manner. All the fields are NULL if the queue is - empty. */ - -static struct - { - gdb_event *first_event; /* First pending event. */ - gdb_event *last_event; /* Last pending event. */ - } -event_queue; +DECLARE_QUEUE_P(gdb_event_p); +DEFINE_QUEUE_P(gdb_event_p); +static QUEUE(gdb_event_p) *event_queue = NULL; /* Gdb_notifier is just a list of file descriptors gdb is interested in. These are the input file descriptor, and the target file @@ -274,41 +255,6 @@ static int gdb_wait_for_event (int); static void poll_timers (void); -/* Insert an event object into the gdb event queue at - the specified position. - POSITION can be head or tail, with values TAIL, HEAD. - EVENT_PTR points to the event to be inserted into the queue. - The caller must allocate memory for the event. It is freed - after the event has ben handled. - Events in the queue will be processed head to tail, therefore, - events inserted at the head of the queue will be processed - as last in first out. Event appended at the tail of the queue - will be processed first in first out. */ -static void -async_queue_event (gdb_event * event_ptr, queue_position position) -{ - if (position == TAIL) - { - /* The event will become the new last_event. */ - - event_ptr->next_event = NULL; - if (event_queue.first_event == NULL) - event_queue.first_event = event_ptr; - else - event_queue.last_event->next_event = event_ptr; - event_queue.last_event = event_ptr; - } - else if (position == HEAD) - { - /* The event becomes the new first_event. */ - - event_ptr->next_event = event_queue.first_event; - if (event_queue.first_event == NULL) - event_queue.last_event = event_ptr; - event_queue.first_event = event_ptr; - } -} - /* Create a generic event, to be enqueued in the event queue for processing. PROC is the procedure associated to the event. DATA is passed to PROC upon PROC invocation. */ @@ -338,6 +284,23 @@ create_file_event (int fd) return create_event (handle_file_event, data); } + +/* Free EVENT. */ + +static void +gdb_event_xfree (struct gdb_event *event) +{ + xfree (event); +} + +/* Initialize the event queue. */ + +void +initialize_event_loop (void) +{ + event_queue = QUEUE_alloc (gdb_event_p, gdb_event_xfree); +} + /* Process one event. The event can be the next one to be serviced in the event queue, or an asynchronous event handler can be invoked in response to @@ -350,10 +313,6 @@ create_file_event (int fd) static int process_event (void) { - gdb_event *event_ptr, *prev_ptr; - event_handler_func *proc; - event_data data; - /* First let's see if there are any asynchronous event handlers that are ready. These would be the result of invoking any of the signal handlers. */ @@ -364,38 +323,20 @@ process_event (void) /* Look in the event queue to find an event that is ready to be processed. */ - for (event_ptr = event_queue.first_event; event_ptr != NULL; - event_ptr = event_ptr->next_event) + if (!QUEUE_is_empty (gdb_event_p, event_queue)) { - /* Call the handler for the event. */ - - proc = event_ptr->proc; - data = event_ptr->data; - /* Let's get rid of the event from the event queue. We need to - do this now because while processing the event, the proc - function could end up calling 'error' and therefore jump out - to the caller of this function, gdb_do_one_event. In that - case, we would have on the event queue an event wich has been - processed, but not deleted. */ - - if (event_queue.first_event == event_ptr) - { - event_queue.first_event = event_ptr->next_event; - if (event_ptr->next_event == NULL) - event_queue.last_event = NULL; - } - else - { - prev_ptr = event_queue.first_event; - while (prev_ptr->next_event != event_ptr) - prev_ptr = prev_ptr->next_event; + do this now because while processing the event, the proc + function could end up calling 'error' and therefore jump out + to the caller of this function, gdb_do_one_event. In that + case, we would have on the event queue an event wich has been + processed, but not deleted. */ + gdb_event *event_ptr = QUEUE_deque (gdb_event_p, event_queue); + /* Call the handler for the event. */ + event_handler_func *proc = event_ptr->proc; + event_data data = event_ptr->data; - prev_ptr->next_event = event_ptr->next_event; - if (event_ptr->next_event == NULL) - event_queue.last_event = prev_ptr; - } - xfree (event_ptr); + gdb_event_xfree (event_ptr); /* Now call the procedure associated with the event. */ (*proc) (data); @@ -936,7 +877,7 @@ gdb_wait_for_event (int block) if (file_ptr->ready_mask == 0) { file_event_ptr = create_file_event (file_ptr->fd); - async_queue_event (file_event_ptr, TAIL); + QUEUE_enque (gdb_event_p, event_queue, file_event_ptr); } file_ptr->ready_mask = (gdb_notifier.poll_fds + i)->revents; } @@ -972,7 +913,7 @@ gdb_wait_for_event (int block) if (file_ptr->ready_mask == 0) { file_event_ptr = create_file_event (file_ptr->fd); - async_queue_event (file_event_ptr, TAIL); + QUEUE_enque (gdb_event_p, event_queue, file_event_ptr); } file_ptr->ready_mask = mask; } @@ -1158,7 +1099,7 @@ check_async_event_handlers (void) data.ptr = hdata; event_ptr = create_event (invoke_async_event_handler, data); - async_queue_event (event_ptr, TAIL); + QUEUE_enque (gdb_event_p, event_queue, event_ptr); } } } @@ -1365,7 +1306,7 @@ poll_timers (void) event_ptr = (gdb_event *) xmalloc (sizeof (gdb_event)); event_ptr->proc = handle_timer_event; event_ptr->data.integer = timer_list.first_timer->timer_id; - async_queue_event (event_ptr, TAIL); + QUEUE_enque (gdb_event_p, event_queue, event_ptr); } /* Now we need to update the timeout for select/ poll, because diff --git a/contrib/gdb-7/gdb/event-loop.h b/contrib/gdb-7/gdb/event-loop.h index fe5d241da5..e994fc138e 100644 --- a/contrib/gdb-7/gdb/event-loop.h +++ b/contrib/gdb-7/gdb/event-loop.h @@ -1,5 +1,5 @@ /* Definitions used by the GDB event loop. - Copyright (C) 1999-2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. Written by Elena Zannoni of Cygnus Solutions. This file is part of GDB. @@ -75,20 +75,9 @@ typedef void (sig_handler_func) (gdb_client_data); typedef void (async_event_handler_func) (gdb_client_data); typedef void (timer_handler_func) (gdb_client_data); -/* Where to add an event onto the event queue, by queue_event. */ -typedef enum - { - /* Add at tail of queue. It will be processed in first in first - out order. */ - TAIL, - /* Add at head of queue. It will be processed in last in first - out order. */ - HEAD - } -queue_position; - /* Exported functions from event-loop.c */ +extern void initialize_event_loop (void); extern void start_event_loop (void); extern int gdb_do_one_event (void); extern void delete_file_handler (int fd); diff --git a/contrib/gdb-7/gdb/event-top.c b/contrib/gdb-7/gdb/event-top.c index 52e78523cf..6f3dfab55e 100644 --- a/contrib/gdb-7/gdb/event-top.c +++ b/contrib/gdb-7/gdb/event-top.c @@ -1,7 +1,6 @@ /* Top level stuff for GDB, the GNU debugger. - Copyright (C) 1999-2002, 2004-2005, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. Written by Elena Zannoni of Cygnus Solutions. @@ -36,6 +35,7 @@ #include "observer.h" #include "continuations.h" #include "gdbcmd.h" /* for dont_repeat() */ +#include "annotate.h" /* readline include files. */ #include "readline/readline.h" @@ -58,9 +58,6 @@ static void handle_sigquit (int sig); static void handle_sighup (int sig); #endif static void handle_sigfpe (int sig); -#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) -static void handle_sigwinch (int sig); -#endif /* Functions to be invoked by the event loop in response to signals. */ @@ -126,19 +123,16 @@ int input_fd; handlers mark these functions as ready to be executed and the event loop, in a later iteration, calls them. See the function invoke_async_signal_handler. */ -void *sigint_token; +static struct async_signal_handler *sigint_token; #ifdef SIGHUP -void *sighup_token; +static struct async_signal_handler *sighup_token; #endif #ifdef SIGQUIT -void *sigquit_token; -#endif -void *sigfpe_token; -#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) -void *sigwinch_token; +static struct async_signal_handler *sigquit_token; #endif +static struct async_signal_handler *sigfpe_token; #ifdef STOP_SIGNAL -void *sigtstp_token; +static struct async_signal_handler *sigtstp_token; #endif /* Structure to save a partially entered command. This is used when @@ -238,6 +232,8 @@ display_gdb_prompt (char *new_prompt) char *actual_gdb_prompt = NULL; struct cleanup *old_chain; + annotate_display_prompt (); + /* Reset the nesting depth used when trace-commands is set. */ reset_command_nest_depth (); @@ -415,7 +411,7 @@ command_handler (char *command) int stdin_is_tty = ISATTY (stdin); struct cleanup *stat_chain; - quit_flag = 0; + clear_quit_flag (); if (instream == stdin && stdin_is_tty) reinitialize_more_filter (); @@ -457,8 +453,6 @@ command_line_handler (char *rl) char *p; char *p1; char *nline; - char got_eof = 0; - int repeat = (instream == stdin); if (annotation_level > 1 && instream == stdin) @@ -503,7 +497,6 @@ command_line_handler (char *rl) and exit from gdb. */ if (!rl || rl == (char *) EOF) { - got_eof = 1; command_handler (0); return; /* Lint. */ } @@ -769,11 +762,6 @@ async_init_signals (void) sigfpe_token = create_async_signal_handler (async_float_handler, NULL); -#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) - signal (SIGWINCH, handle_sigwinch); - sigwinch_token = - create_async_signal_handler (SIGWINCH_HANDLER, NULL); -#endif #ifdef STOP_SIGNAL sigtstp_token = create_async_signal_handler (async_stop_sig, NULL); @@ -781,12 +769,6 @@ async_init_signals (void) } -void -mark_async_signal_handler_wrapper (void *token) -{ - mark_async_signal_handler ((struct async_signal_handler *) token); -} - /* Tell the event loop what to do if SIGINT is received. See event-signal.c. */ void @@ -799,7 +781,7 @@ handle_sigint (int sig) set quit_flag to 1 here. Then if QUIT is called before we get to the event loop, we will unwind as expected. */ - quit_flag = 1; + set_quit_flag (); /* If immediate_quit is set, we go ahead and process the SIGINT right away, even if we usually would defer this to the event loop. The @@ -828,10 +810,9 @@ async_request_quit (gdb_client_data arg) /* If the quit_flag has gotten reset back to 0 by the time we get back here, that means that an exception was thrown to unwind the current command before we got back to the event loop. So there - is no reason to call quit again here, unless immediate_quit is - set. */ + is no reason to call quit again here. */ - if (quit_flag || immediate_quit) + if (check_quit_flag ()) quit (); } @@ -841,7 +822,7 @@ async_request_quit (gdb_client_data arg) static void handle_sigquit (int sig) { - mark_async_signal_handler_wrapper (sigquit_token); + mark_async_signal_handler (sigquit_token); signal (sig, handle_sigquit); } #endif @@ -862,7 +843,7 @@ async_do_nothing (gdb_client_data arg) static void handle_sighup (int sig) { - mark_async_signal_handler_wrapper (sighup_token); + mark_async_signal_handler (sighup_token); signal (sig, handle_sighup); } @@ -898,7 +879,7 @@ async_disconnect (gdb_client_data arg) void handle_stop_sig (int sig) { - mark_async_signal_handler_wrapper (sigtstp_token); + mark_async_signal_handler (sigtstp_token); signal (sig, handle_stop_sig); } @@ -938,7 +919,7 @@ async_stop_sig (gdb_client_data arg) static void handle_sigfpe (int sig) { - mark_async_signal_handler_wrapper (sigfpe_token); + mark_async_signal_handler (sigfpe_token); signal (sig, handle_sigfpe); } @@ -950,17 +931,6 @@ async_float_handler (gdb_client_data arg) divide by zero causes this, so "float" is a misnomer. */ error (_("Erroneous arithmetic operation.")); } - -/* Tell the event loop what to do if SIGWINCH is received. - See event-signal.c. */ -#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) -static void -handle_sigwinch (int sig) -{ - mark_async_signal_handler_wrapper (sigwinch_token); - signal (sig, handle_sigwinch); -} -#endif /* Called by do_setshow_command. */ diff --git a/contrib/gdb-7/gdb/event-top.h b/contrib/gdb-7/gdb/event-top.h index 76a790e613..e6166f6a72 100644 --- a/contrib/gdb-7/gdb/event-top.h +++ b/contrib/gdb-7/gdb/event-top.h @@ -1,7 +1,6 @@ /* Definitions used by event-top.c, for GDB, the GNU debugger. - Copyright (C) 1999, 2001, 2003, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. Written by Elena Zannoni of Cygnus Solutions. @@ -46,7 +45,6 @@ extern void handle_stop_sig (int sig); extern void handle_sigint (int sig); extern void handle_sigterm (int sig); extern void gdb_readline2 (void *client_data); -extern void mark_async_signal_handler_wrapper (void *token); extern void async_request_quit (void *arg); extern void stdin_event_handler (int error, void *client_data); extern void async_disable_stdin (void); diff --git a/contrib/gdb-7/gdb/exceptions.c b/contrib/gdb-7/gdb/exceptions.c index 2ac1283b2f..866905d7cf 100644 --- a/contrib/gdb-7/gdb/exceptions.c +++ b/contrib/gdb-7/gdb/exceptions.c @@ -1,6 +1,6 @@ /* Exception (throw catch) mechanism, for GDB, the GNU debugger. - Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -66,6 +66,22 @@ struct catcher /* Where to go for throw_exception(). */ static struct catcher *current_catcher; +/* Return length of current_catcher list. */ + +static int +catcher_list_size (void) +{ + int size; + struct catcher *catcher; + + for (size = 0, catcher = current_catcher; + catcher != NULL; + catcher = catcher->prev) + ++size; + + return size; +} + EXCEPTIONS_SIGJMP_BUF * exceptions_state_mc_init (volatile struct gdb_exception *exception, return_mask mask) @@ -205,10 +221,10 @@ exceptions_state_mc_action_iter_1 (void) void throw_exception (struct gdb_exception exception) { - quit_flag = 0; + clear_quit_flag (); immediate_quit = 0; - do_cleanups (ALL_CLEANUPS); + do_cleanups (all_cleanups ()); /* Jump to the containing catch_errors() call, communicating REASON to that call via setjmp's return value. Note that REASON can't @@ -218,8 +234,6 @@ throw_exception (struct gdb_exception exception) EXCEPTIONS_SIGLONGJMP (current_catcher->buf, exception.reason); } -static char *last_message; - void deprecated_throw_reason (enum return_reason reason) { @@ -357,23 +371,53 @@ print_any_exception (struct ui_file *file, const char *prefix, } } +/* A stack of exception messages. + This is needed to handle nested calls to throw_it: we don't want to + xfree space for a message before it's used. + This can happen if we throw an exception during a cleanup: + An outer TRY_CATCH may have an exception message it wants to print, + but while doing cleanups further calls to throw_it are made. + + This is indexed by the size of the current_catcher list. + It is a dynamically allocated array so that we don't care how deeply + GDB nests its TRY_CATCHs. */ +static char **exception_messages; + +/* The number of currently allocated entries in exception_messages. */ +static int exception_messages_size; + static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0) throw_it (enum return_reason reason, enum errors error, const char *fmt, va_list ap) { struct gdb_exception e; char *new_message; + int depth = catcher_list_size (); + + gdb_assert (depth > 0); - /* Save the message. Create the new message before deleting the - old, the new message may include the old message text. */ + /* Note: The new message may use an old message's text. */ new_message = xstrvprintf (fmt, ap); - xfree (last_message); - last_message = new_message; + + if (depth > exception_messages_size) + { + int old_size = exception_messages_size; + + exception_messages_size = depth + 10; + exception_messages = (char **) xrealloc (exception_messages, + exception_messages_size + * sizeof (char *)); + memset (exception_messages + old_size, 0, + (exception_messages_size - old_size) * sizeof (char *)); + } + + xfree (exception_messages[depth - 1]); + exception_messages[depth - 1] = new_message; /* Create the exception. */ e.reason = reason; e.error = error; - e.message = last_message; + e.message = new_message; /* Throw the exception. */ throw_exception (e); diff --git a/contrib/gdb-7/gdb/exceptions.h b/contrib/gdb-7/gdb/exceptions.h index 0c59a25f1f..630eb2e56b 100644 --- a/contrib/gdb-7/gdb/exceptions.h +++ b/contrib/gdb-7/gdb/exceptions.h @@ -1,6 +1,6 @@ /* Exception (throw catch) mechanism, for GDB, the GNU debugger. - Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -86,6 +86,10 @@ enum errors { /* DW_OP_GNU_entry_value resolving failed. */ NO_ENTRY_VALUE_ERROR, + /* Target throwing an error has been closed. Current command should be + aborted as the inferior state is no longer valid. */ + TARGET_CLOSE_ERROR, + /* Add more errors here. */ NR_ERRORS }; diff --git a/contrib/gdb-7/gdb/exec.c b/contrib/gdb-7/gdb/exec.c index cd129f7cbc..92c44f303f 100644 --- a/contrib/gdb-7/gdb/exec.c +++ b/contrib/gdb-7/gdb/exec.c @@ -1,6 +1,6 @@ /* Work with executable files, for GDB. - Copyright (C) 1988-2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1988-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -33,6 +33,7 @@ #include "arch-utils.h" #include "gdbthread.h" #include "progspace.h" +#include "gdb_bfd.h" #include #include "readline/readline.h" @@ -98,17 +99,18 @@ exec_close (void) if (exec_bfd) { bfd *abfd = exec_bfd; - char *name = bfd_get_filename (abfd); - gdb_bfd_close_or_warn (abfd); - xfree (name); + gdb_bfd_unref (abfd); /* Removing target sections may close the exec_ops target. Clear exec_bfd before doing so to prevent recursion. */ exec_bfd = NULL; exec_bfd_mtime = 0; - remove_target_sections (abfd); + remove_target_sections (&exec_bfd, abfd); + + xfree (exec_filename); + exec_filename = NULL; } } @@ -118,7 +120,6 @@ exec_close (void) static void exec_close_1 (int quitting) { - int need_symtab_cleanup = 0; struct vmap *vp, *nxt; using_exec_ops = 0; @@ -128,17 +129,10 @@ exec_close_1 (int quitting) vp = nxt; nxt = vp->nxt; - /* if there is an objfile associated with this bfd, - free_objfile() will do proper cleanup of objfile *and* bfd. */ - if (vp->objfile) - { - free_objfile (vp->objfile); - need_symtab_cleanup = 1; - } - else if (vp->bfd != exec_bfd) - /* FIXME-leak: We should be freeing vp->name too, I think. */ - gdb_bfd_close_or_warn (vp->bfd); + free_objfile (vp->objfile); + + gdb_bfd_unref (vp->bfd); xfree (vp); } @@ -211,12 +205,13 @@ exec_file_attach (char *filename, int from_tty) else { struct cleanup *cleanups; - char *scratch_pathname; + char *scratch_pathname, *canonical_pathname; int scratch_chan; struct target_section *sections = NULL, *sections_end = NULL; char **matching; - scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename, + scratch_chan = openp (getenv ("PATH"), + OPF_TRY_CWD_FIRST | OPF_DISABLE_REALPATH, filename, write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, &scratch_pathname); #if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__) @@ -225,30 +220,37 @@ exec_file_attach (char *filename, int from_tty) char *exename = alloca (strlen (filename) + 5); strcat (strcpy (exename, filename), ".exe"); - scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, exename, + scratch_chan = openp (getenv ("PATH"), + OPF_TRY_CWD_FIRST | OPF_DISABLE_REALPATH, + exename, write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, &scratch_pathname); } #endif if (scratch_chan < 0) perror_with_name (filename); - exec_bfd = bfd_fopen (scratch_pathname, gnutarget, - write_files ? FOPEN_RUB : FOPEN_RB, - scratch_chan); + + cleanups = make_cleanup (xfree, scratch_pathname); + + /* gdb_bfd_open (and its variants) prefers canonicalized pathname for + better BFD caching. */ + canonical_pathname = gdb_realpath (scratch_pathname); + make_cleanup (xfree, canonical_pathname); + + if (write_files) + exec_bfd = gdb_bfd_fopen (canonical_pathname, gnutarget, + FOPEN_RUB, scratch_chan); + else + exec_bfd = gdb_bfd_open (canonical_pathname, gnutarget, scratch_chan); if (!exec_bfd) { - close (scratch_chan); error (_("\"%s\": could not open as an executable file: %s"), scratch_pathname, bfd_errmsg (bfd_get_error ())); } - /* At this point, scratch_pathname and exec_bfd->name both point to the - same malloc'd string. However exec_close() will attempt to free it - via the exec_bfd->name pointer, so we need to make another copy and - leave exec_bfd as the new owner of the original copy. */ - scratch_pathname = xstrdup (scratch_pathname); - cleanups = make_cleanup (xfree, scratch_pathname); + gdb_assert (exec_filename == NULL); + exec_filename = xstrdup (scratch_pathname); if (!bfd_check_format_matches (exec_bfd, bfd_object, &matching)) { @@ -294,7 +296,7 @@ exec_file_attach (char *filename, int from_tty) /* Add the executable's sections to the current address spaces' list of sections. This possibly pushes the exec_ops target. */ - add_target_sections (sections, sections_end); + add_target_sections (&exec_bfd, sections, sections_end); xfree (sections); /* Tell display code (if any) about the changed file name. */ @@ -388,6 +390,7 @@ add_to_section_table (bfd *abfd, struct bfd_section *asect, if (!(aflag & SEC_ALLOC)) return; + (*table_pp)->key = NULL; (*table_pp)->bfd = abfd; (*table_pp)->the_bfd_section = asect; (*table_pp)->addr = bfd_section_vma (abfd, asect); @@ -398,11 +401,9 @@ add_to_section_table (bfd *abfd, struct bfd_section *asect, int resize_section_table (struct target_section_table *table, int num_added) { - struct target_section *old_value; int old_count; int new_count; - old_value = table->sections; old_count = table->sections_end - table->sections; new_count = num_added + old_count; @@ -448,7 +449,8 @@ build_section_table (struct bfd *some_bfd, struct target_section **start, current set of target sections. */ void -add_target_sections (struct target_section *sections, +add_target_sections (void *key, + struct target_section *sections, struct target_section *sections_end) { int count; @@ -459,9 +461,13 @@ add_target_sections (struct target_section *sections, if (count > 0) { int space = resize_section_table (table, count); + int i; - memcpy (table->sections + space, - sections, count * sizeof (sections[0])); + for (i = 0; i < count; ++i) + { + table->sections[space + i] = sections[i]; + table->sections[space + i].key = key; + } /* If these are the first file sections we can provide memory from, push the file_stratum target. */ @@ -476,14 +482,14 @@ add_target_sections (struct target_section *sections, /* Remove all target sections taken from ABFD. */ void -remove_target_sections (bfd *abfd) +remove_target_sections (void *key, bfd *abfd) { struct target_section *src, *dest; struct target_section_table *table = current_target_sections; dest = table->sections; for (src = table->sections; src < table->sections_end; src++) - if (src->bfd != abfd) + if (src->key != key || src->bfd != abfd) { /* Keep this section. */ if (dest < src) @@ -555,6 +561,7 @@ map_vmap (bfd *abfd, bfd *arch) memset ((char *) vp, '\0', sizeof (*vp)); vp->nxt = 0; vp->bfd = abfd; + gdb_bfd_ref (abfd); vp->name = bfd_get_filename (arch ? arch : abfd); vp->member = arch ? bfd_get_filename (abfd) : ""; @@ -667,7 +674,7 @@ section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, return 0; /* We can't help. */ } -struct target_section_table * +static struct target_section_table * exec_get_section_table (struct target_ops *ops) { return current_target_sections; @@ -761,11 +768,14 @@ print_section_info (struct target_section_table *t, bfd *abfd) static void exec_files_info (struct target_ops *t) { - print_section_info (current_target_sections, exec_bfd); + if (exec_bfd) + print_section_info (current_target_sections, exec_bfd); + else + puts_filtered (_("\t\n")); if (vmap) { - int addr_size = gdbarch_addr_bit (target_gdbarch) / 8; + int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8; struct vmap *vp; printf_unfiltered (_("\tMapping info for file `%s'.\n"), vmap->name); @@ -813,9 +823,9 @@ set_section_command (char *args, int from_tty) table = current_target_sections; for (p = table->sections; p < table->sections_end; p++) { - if (!strncmp (secname, bfd_section_name (exec_bfd, + if (!strncmp (secname, bfd_section_name (p->bfd, p->the_bfd_section), seclen) - && bfd_section_name (exec_bfd, p->the_bfd_section)[seclen] == '\0') + && bfd_section_name (p->bfd, p->the_bfd_section)[seclen] == '\0') { offset = secaddr - p->addr; p->addr += offset; diff --git a/contrib/gdb-7/gdb/exec.h b/contrib/gdb-7/gdb/exec.h index a0f9eaba6d..39d3730aab 100644 --- a/contrib/gdb-7/gdb/exec.h +++ b/contrib/gdb-7/gdb/exec.h @@ -1,6 +1,6 @@ /* Work with executable files, for GDB, the GNU debugger. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -32,6 +32,7 @@ extern struct target_ops exec_ops; #define exec_bfd current_program_space->ebfd #define exec_bfd_mtime current_program_space->ebfd_mtime +#define exec_filename current_program_space->pspace_exec_filename /* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR. Returns 0 if OK, 1 on error. */ @@ -83,12 +84,13 @@ extern void exec_set_section_address (const char *, int, CORE_ADDR); /* Remove all target sections taken from ABFD. */ -extern void remove_target_sections (bfd *abfd); +extern void remove_target_sections (void *key, bfd *abfd); /* Add the sections array defined by [SECTIONS..SECTIONS_END[ to the current set of target sections. */ -extern void add_target_sections (struct target_section *sections, +extern void add_target_sections (void *key, + struct target_section *sections, struct target_section *sections_end); /* Prints info about all sections defined in the TABLE. ABFD is diff --git a/contrib/gdb-7/gdb/expprint.c b/contrib/gdb-7/gdb/expprint.c index d9d9b8fc87..69055348cf 100644 --- a/contrib/gdb-7/gdb/expprint.c +++ b/contrib/gdb-7/gdb/expprint.c @@ -1,7 +1,6 @@ /* Print in infix form a struct expression. - Copyright (C) 1986, 1988-1989, 1991-2000, 2003, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -33,9 +32,7 @@ #include "gdb_assert.h" #include "valprint.h" -#ifdef HAVE_CTYPE_H #include -#endif void print_expression (struct expression *exp, struct ui_file *stream) @@ -83,6 +80,11 @@ print_subexp_standard (struct expression *exp, int *pos, { /* Common ops */ + case OP_TYPE: + (*pos) += 2; + type_print (exp->elts[pc + 1].type, "", stream, 0); + return; + case OP_SCOPE: myprec = PREC_PREFIX; assoc = 0; @@ -119,7 +121,7 @@ print_subexp_standard (struct expression *exp, int *pos, case OP_VAR_VALUE: { - struct block *b; + const struct block *b; (*pos) += 3; b = exp->elts[pc + 1].block; @@ -136,8 +138,6 @@ print_subexp_standard (struct expression *exp, int *pos, case OP_VAR_ENTRY_VALUE: { - struct block *b; - (*pos) += 2; fprintf_filtered (stream, "%s@entry", SYMBOL_PRINT_NAME (exp->elts[pc + 1].symbol)); @@ -203,17 +203,11 @@ print_subexp_standard (struct expression *exp, int *pos, additional parameter to LA_PRINT_STRING. -fnf */ get_user_print_options (&opts); LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, - &exp->elts[pc + 2].string, nargs, NULL, 0, &opts); + (gdb_byte *) &exp->elts[pc + 2].string, nargs, + NULL, 0, &opts); } return; - case OP_BITSTRING: - nargs = longest_to_int (exp->elts[pc + 1].longconst); - (*pos) - += 3 + BYTES_TO_EXP_ELEM ((nargs + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT); - fprintf_unfiltered (stream, "B''"); - return; - case OP_OBJC_NSSTRING: /* Objective-C Foundation Class NSString constant. */ { @@ -224,7 +218,8 @@ print_subexp_standard (struct expression *exp, int *pos, fputs_filtered ("@\"", stream); get_user_print_options (&opts); LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, - &exp->elts[pc + 2].string, nargs, NULL, 0, &opts); + (gdb_byte *) &exp->elts[pc + 2].string, nargs, + NULL, 0, &opts); fputs_filtered ("\"", stream); } return; @@ -314,7 +309,7 @@ print_subexp_standard (struct expression *exp, int *pos, get_user_print_options (&opts); LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, - tempstr, nargs - 1, NULL, 0, &opts); + (gdb_byte *) tempstr, nargs - 1, NULL, 0, &opts); (*pos) = pc; } else @@ -332,21 +327,6 @@ print_subexp_standard (struct expression *exp, int *pos, } return; - case OP_LABELED: - tem = longest_to_int (exp->elts[pc + 1].longconst); - (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); - /* Gcc support both these syntaxes. Unsure which is preferred. */ -#if 1 - fputs_filtered (&exp->elts[pc + 2].string, stream); - fputs_filtered (": ", stream); -#else - fputs_filtered (".", stream); - fputs_filtered (&exp->elts[pc + 2].string, stream); - fputs_filtered ("=", stream); -#endif - print_subexp (exp, pos, stream, PREC_SUFFIX); - return; - case TERNOP_COND: if ((int) prec > (int) PREC_COMMA) fputs_filtered ("(", stream); @@ -364,7 +344,6 @@ print_subexp_standard (struct expression *exp, int *pos, return; case TERNOP_SLICE: - case TERNOP_SLICE_COUNT: print_subexp (exp, pos, stream, PREC_SUFFIX); fputs_filtered ("(", stream); print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); @@ -431,13 +410,23 @@ print_subexp_standard (struct expression *exp, int *pos, fputs_filtered (")", stream); return; + case UNOP_CAST_TYPE: + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered ("(", stream); + fputs_filtered ("(", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + fputs_filtered (") ", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered (")", stream); + return; + case UNOP_DYNAMIC_CAST: case UNOP_REINTERPRET_CAST: fputs_filtered (opcode == UNOP_DYNAMIC_CAST ? "dynamic_cast" : "reinterpret_cast", stream); fputs_filtered ("<", stream); - (*pos) += 2; - type_print (exp->elts[pc + 1].type, "", stream, 0); + print_subexp (exp, pos, stream, PREC_PREFIX); fputs_filtered ("> (", stream); print_subexp (exp, pos, stream, PREC_PREFIX); fputs_filtered (")", stream); @@ -473,6 +462,17 @@ print_subexp_standard (struct expression *exp, int *pos, fputs_filtered (")", stream); return; + case UNOP_MEMVAL_TYPE: + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered ("(", stream); + fputs_filtered ("{", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + fputs_filtered ("} ", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered (")", stream); + return; + case UNOP_MEMVAL_TLS: (*pos) += 3; if ((int) prec > (int) PREC_PREFIX) @@ -647,12 +647,11 @@ op_string (enum exp_opcode op) /* Support for dumping the raw data from expressions in a human readable form. */ -static char *op_name (struct expression *, enum exp_opcode); static int dump_subexp_body (struct expression *exp, struct ui_file *, int); /* Name for OPCODE, when it appears in expression EXP. */ -static char * +char * op_name (struct expression *exp, enum exp_opcode opcode) { return exp->language_defn->la_exp_desc->op_name (opcode); @@ -670,7 +669,7 @@ op_name_standard (enum exp_opcode opcode) { static char buf[30]; - sprintf (buf, "", opcode); + xsnprintf (buf, sizeof (buf), "", opcode); return buf; } #define OP(name) \ @@ -771,7 +770,6 @@ dump_subexp_body_standard (struct expression *exp, { case TERNOP_COND: case TERNOP_SLICE: - case TERNOP_SLICE_COUNT: elt = dump_subexp (exp, stream, elt); /* FALL THROUGH */ case BINOP_ADD: @@ -913,10 +911,17 @@ dump_subexp_body_standard (struct expression *exp, elt = dump_subexp (exp, stream, elt); } break; - case UNOP_MEMVAL: - case UNOP_CAST: case UNOP_DYNAMIC_CAST: case UNOP_REINTERPRET_CAST: + case UNOP_CAST_TYPE: + case UNOP_MEMVAL_TYPE: + fprintf_filtered (stream, " ("); + elt = dump_subexp (exp, stream, elt); + fprintf_filtered (stream, ")"); + elt = dump_subexp (exp, stream, elt); + break; + case UNOP_MEMVAL: + case UNOP_CAST: fprintf_filtered (stream, "Type @"); gdb_print_host_address (exp->elts[elt].type, stream); fprintf_filtered (stream, " ("); @@ -942,6 +947,12 @@ dump_subexp_body_standard (struct expression *exp, fprintf_filtered (stream, ")"); elt += 2; break; + case OP_TYPEOF: + case OP_DECLTYPE: + fprintf_filtered (stream, "Typeof ("); + elt = dump_subexp (exp, stream, elt); + fprintf_filtered (stream, ")"); + break; case STRUCTOP_STRUCT: case STRUCTOP_PTR: { @@ -975,7 +986,6 @@ dump_subexp_body_standard (struct expression *exp, break; case TYPE_INSTANCE: { - char *elem_name; LONGEST len; len = exp->elts[elt++].longconst; @@ -1002,11 +1012,9 @@ dump_subexp_body_standard (struct expression *exp, case OP_F77_UNDETERMINED_ARGLIST: case OP_COMPLEX: case OP_STRING: - case OP_BITSTRING: case OP_BOOL: case OP_M2_STRING: case OP_THIS: - case OP_LABELED: case OP_NAME: fprintf_filtered (stream, "Unknown format"); } @@ -1022,10 +1030,7 @@ dump_prefix_expression (struct expression *exp, struct ui_file *stream) fprintf_filtered (stream, "Dump of expression @ "); gdb_print_host_address (exp, stream); fputs_filtered (", after conversion to prefix form:\nExpression: `", stream); - if (exp->elts[0].opcode != OP_TYPE) - print_expression (exp, stream); - else - fputs_filtered ("Type printing not yet supported....", stream); + print_expression (exp, stream); fprintf_filtered (stream, "'\n\tLanguage %s, %d elements, %ld bytes each.\n", exp->language_defn->la_name, exp->nelts, (long) sizeof (union exp_element)); diff --git a/contrib/gdb-7/gdb/expression.h b/contrib/gdb-7/gdb/expression.h index be26002998..eea47dc6b2 100644 --- a/contrib/gdb-7/gdb/expression.h +++ b/contrib/gdb-7/gdb/expression.h @@ -1,7 +1,6 @@ /* Definitions for expressions stored in reversed prefix form, for GDB. - Copyright (C) 1986, 1989, 1992, 1994, 2000, 2003, 2005, 2007-2012 - Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -73,7 +72,7 @@ union exp_element char string; struct type *type; struct internalvar *internalvar; - struct block *block; + const struct block *block; struct objfile *objfile; }; @@ -96,20 +95,22 @@ struct expression /* From parse.c */ -extern struct expression *parse_expression (char *); +extern struct expression *parse_expression (const char *); -extern struct type *parse_field_expression (char *, char **); +extern struct type *parse_expression_for_completion (char *, char **, + enum type_code *); -extern struct expression *parse_exp_1 (char **, struct block *, int); +extern struct expression *parse_exp_1 (const char **, CORE_ADDR pc, + const struct block *, int); /* For use by parsers; set if we want to parse an expression and - attempt to complete a field name. */ -extern int in_parse_field; + attempt completion. */ +extern int parse_completion; /* The innermost context required by the stack and register variables we've encountered so far. To use this, set it to NULL, then call parse_, then look at it. */ -extern struct block *innermost_block; +extern const struct block *innermost_block; /* From eval.c */ @@ -137,6 +138,8 @@ extern struct value *evaluate_subexp_standard extern void print_expression (struct expression *, struct ui_file *); +extern char *op_name (struct expression *exp, enum exp_opcode opcode); + extern char *op_string (enum exp_opcode); extern void dump_raw_expression (struct expression *, diff --git a/contrib/gdb-7/gdb/f-exp.y b/contrib/gdb-7/gdb/f-exp.y index fa464cf7ed..846cc02b3b 100644 --- a/contrib/gdb-7/gdb/f-exp.y +++ b/contrib/gdb-7/gdb/f-exp.y @@ -1,6 +1,5 @@ /* YACC parser for Fortran expressions, for GDB. - Copyright (C) 1986, 1989-1991, 1993-1996, 2000-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. Contributed by Motorola. Adapted from the C parser by Farooq Butt (fmbutt@engage.sps.mot.com). @@ -105,6 +104,12 @@ #define yygindex f_yygindex #define yytable f_yytable #define yycheck f_yycheck +#define yyss f_yyss +#define yysslim f_yysslim +#define yyssp f_yyssp +#define yystacksize f_yystacksize +#define yyvs f_yyvs +#define yyvsp f_yyvsp #ifndef YYDEBUG #define YYDEBUG 1 /* Default to yydebug support */ @@ -664,11 +669,7 @@ name_not_typename : NAME /*** Needs some error checking for the float case ***/ static int -parse_number (p, len, parsed_float, putithere) - char *p; - int len; - int parsed_float; - YYSTYPE *putithere; +parse_number (char *p, int len, int parsed_float, YYSTYPE *putithere) { LONGEST n = 0; LONGEST prevn = 0; @@ -895,8 +896,7 @@ static int tempbufindex; /* Current index into buffer */ first one on demand. */ static void -growbuf_by_size (count) - int count; +growbuf_by_size (int count) { int growby; @@ -1174,9 +1174,13 @@ yylex (void) { char *tmp = copy_name (yylval.sval); struct symbol *sym; - int is_a_field_of_this = 0; + struct field_of_this_result is_a_field_of_this; int hextype; + /* Initialize this in case we *don't* use it in this call; that + way we can refer to it unconditionally below. */ + memset (&is_a_field_of_this, 0, sizeof (is_a_field_of_this)); + sym = lookup_symbol (tmp, expression_context_block, VAR_DOMAIN, parse_language->la_language == language_cplus @@ -1204,21 +1208,20 @@ yylex (void) if (hextype == INT) { yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; + yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL; return NAME_OR_INT; } } /* Any other kind of symbol */ yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; + yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL; return NAME; } } void -yyerror (msg) - char *msg; +yyerror (char *msg) { if (prev_lexptr) lexptr = prev_lexptr; diff --git a/contrib/gdb-7/gdb/f-lang.c b/contrib/gdb-7/gdb/f-lang.c index 4149cefc09..652da79ad7 100644 --- a/contrib/gdb-7/gdb/f-lang.c +++ b/contrib/gdb-7/gdb/f-lang.c @@ -1,7 +1,6 @@ /* Fortran language support routines for GDB, the GNU debugger. - Copyright (C) 1993-1996, 1998-2005, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1993-2013 Free Software Foundation, Inc. Contributed by Motorola. Adapted from the C parser by Farooq Butt (fmbutt@engage.sps.mot.com). @@ -33,45 +32,12 @@ #include "value.h" #include "cp-support.h" #include "charset.h" +#include "c-lang.h" -/* Following is dubious stuff that had been in the xcoff reader. */ - -struct saved_fcn - { - long line_offset; /* Line offset for function. */ - struct saved_fcn *next; - }; - - -struct saved_bf_symnum - { - long symnum_fcn; /* Symnum of function (i.e. .function - directive). */ - long symnum_bf; /* Symnum of .bf for this function. */ - struct saved_bf_symnum *next; - }; - -typedef struct saved_fcn SAVED_FUNCTION, *SAVED_FUNCTION_PTR; -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 type *type, struct ui_file * stream); static void f_emit_char (int c, struct type *type, @@ -262,23 +228,17 @@ f_word_break_characters (void) /* Consider the modules separator :: as a valid symbol name character class. */ -static char ** -f_make_symbol_completion_list (char *text, char *word) +static VEC (char_ptr) * +f_make_symbol_completion_list (char *text, char *word, enum type_code code) { - return default_make_symbol_completion_list_break_on (text, word, ":"); + return default_make_symbol_completion_list_break_on (text, word, ":", code); } -/* This is declared in c-lang.h but it is silly to import that file for what - is already just a hack. */ -extern int c_value_print (struct value *, struct ui_file *, - const struct value_print_options *); - const struct language_defn f_language_defn = { "fortran", language_fortran, range_check_on, - type_check_on, case_sensitive_off, array_column_major, macro_expansion_no, @@ -293,6 +253,7 @@ const struct language_defn f_language_defn = default_print_typedef, /* Print a typedef using appropriate syntax */ f_val_print, /* Print a value using appropriate syntax */ c_value_print, /* FIXME */ + default_read_var_value, /* la_read_var_value */ NULL, /* Language specific skip_trampoline */ NULL, /* name_of_this */ cp_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ @@ -309,7 +270,7 @@ const struct language_defn f_language_defn = default_print_array_index, default_pass_by_reference, default_get_string, - strcmp_iw_ordered, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, LANG_MAGIC }; @@ -387,395 +348,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/contrib/gdb-7/gdb/f-lang.h b/contrib/gdb-7/gdb/f-lang.h index 3a46ebf67a..4ef1acfcaf 100644 --- a/contrib/gdb-7/gdb/f-lang.h +++ b/contrib/gdb-7/gdb/f-lang.h @@ -1,7 +1,6 @@ /* Fortran language support definitions for GDB, the GNU debugger. - Copyright (C) 1992-1995, 1998, 2000, 2005, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. Contributed by Motorola. Adapted from the C definitions by Farooq Butt (fmbutt@engage.sps.mot.com). @@ -21,17 +20,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +struct type_print_options; + extern int f_parse (void); extern void f_error (char *); /* Defined in f-exp.y */ extern void f_print_type (struct type *, const char *, struct ui_file *, int, - int); + int, const struct type_print_options *); -extern int f_val_print (struct type *, const gdb_byte *, int, CORE_ADDR, - struct ui_file *, int, - const struct value *, - const struct value_print_options *); +extern void f_val_print (struct type *, const gdb_byte *, int, CORE_ADDR, + struct ui_file *, int, + const struct value *, + const struct value_print_options *); /* Language-specific data structures */ @@ -48,52 +49,17 @@ 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; +/* A common block. */ -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 - therefore no way of knowing the bounds of stack-based arrays, - we have to assign default bounds, these are as good as any... */ - -#define DEFAULT_UPPER_BOUND 999999 -#define DEFAULT_LOWER_BOUND -999999 +struct common_block +{ + /* The number of entries in the block. */ + size_t n_entries; -extern char *real_main_name; /* Name of main function. */ -extern int real_main_c_value; /* C_value field of main function. */ + /* The contents of the block, allocated using the struct hack. All + pointers in the array are non-NULL. */ + struct symbol *contents[1]; +}; extern int f77_get_upperbound (struct type *); diff --git a/contrib/gdb-7/gdb/f-typeprint.c b/contrib/gdb-7/gdb/f-typeprint.c index a95ef8449c..aa33231a5c 100644 --- a/contrib/gdb-7/gdb/f-typeprint.c +++ b/contrib/gdb-7/gdb/f-typeprint.c @@ -1,7 +1,6 @@ /* Support for printing Fortran types for GDB, the GNU debugger. - Copyright (C) 1986, 1988-1989, 1991, 1993-1996, 1998, 2000-2003, - 2006-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. Contributed by Motorola. Adapted from the C version by Farooq Butt (fmbutt@engage.sps.mot.com). @@ -52,7 +51,7 @@ void f_type_print_base (struct type *, struct ui_file *, int, int); void f_print_type (struct type *type, const char *varstring, struct ui_file *stream, - int show, int level) + int show, int level, const struct type_print_options *flags) { enum type_code code; int demangled_args; @@ -131,7 +130,6 @@ f_type_print_varspec_prefix (struct type *type, struct ui_file *stream, case TYPE_CODE_SET: case TYPE_CODE_RANGE: case TYPE_CODE_STRING: - case TYPE_CODE_BITSTRING: case TYPE_CODE_METHOD: case TYPE_CODE_REF: case TYPE_CODE_COMPLEX: @@ -230,7 +228,6 @@ f_type_print_varspec_suffix (struct type *type, struct ui_file *stream, case TYPE_CODE_SET: case TYPE_CODE_RANGE: case TYPE_CODE_STRING: - case TYPE_CODE_BITSTRING: case TYPE_CODE_METHOD: case TYPE_CODE_COMPLEX: case TYPE_CODE_TYPEDEF: diff --git a/contrib/gdb-7/gdb/f-valprint.c b/contrib/gdb-7/gdb/f-valprint.c index 87b2ed1a1a..d01d6ec7a4 100644 --- a/contrib/gdb-7/gdb/f-valprint.c +++ b/contrib/gdb-7/gdb/f-valprint.c @@ -1,7 +1,6 @@ /* Support for printing Fortran values for GDB, the GNU debugger. - Copyright (C) 1993-1996, 1998-2000, 2003, 2005-2012 Free Software - Foundation, Inc. + Copyright (C) 1993-2013 Free Software Foundation, Inc. Contributed by Motorola. Adapted from the C definitions by Farooq Butt (fmbutt@engage.sps.mot.com), additionally worked over by Stan Shebs. @@ -34,14 +33,12 @@ #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" +#include "exceptions.h" extern void _initialize_f_valprint (void); static void info_common_command (char *, int); -static void list_all_visible_commons (char *); static void f77_create_arrayprint_offset_tbl (struct type *, struct ui_file *); static void f77_get_dynamic_length_of_aggregate (struct type *); @@ -130,7 +127,7 @@ f77_create_arrayprint_offset_tbl (struct type *type, struct ui_file *stream) tmp_type = type; - while ((TYPE_CODE (tmp_type) == TYPE_CODE_ARRAY)) + while (TYPE_CODE (tmp_type) == TYPE_CODE_ARRAY) { upper = f77_get_upperbound (tmp_type); lower = f77_get_lowerbound (tmp_type); @@ -242,11 +239,22 @@ Type node corrupt! F77 arrays cannot have %d subscripts (%d Max)"), } +/* Decorations for Fortran. */ + +static const struct generic_val_print_decorations f_decorations = +{ + "(", + ",", + ")", + ".TRUE.", + ".FALSE.", + "VOID", +}; + /* See val_print for a description of the various parameters of this - function; they are identical. The semantics of the return value is - also identical to val_print. */ + function; they are identical. */ -int +void f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR address, struct ui_file *stream, int recurse, const struct value *original_value, @@ -256,7 +264,6 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); unsigned int i = 0; /* Number of characters printed. */ struct type *elttype; - LONGEST val; CORE_ADDR addr; int index; @@ -299,19 +306,26 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, } else { + int want_space = 0; + addr = unpack_pointer (type, valaddr + embedded_offset); elttype = check_typedef (TYPE_TARGET_TYPE (type)); if (TYPE_CODE (elttype) == TYPE_CODE_FUNC) { /* Try to print what function it points to. */ - print_address_demangle (gdbarch, addr, stream, demangle); - /* Return value is irrelevant except for string pointers. */ - return 0; + print_function_pointer_address (options, gdbarch, addr, stream); + return; } - if (options->addressprint && options->format != 's') - fputs_filtered (paddress (gdbarch, addr), stream); + if (options->symbol_print) + want_space = print_address_demangle (options, gdbarch, addr, + stream, demangle); + else if (options->addressprint && options->format != 's') + { + fputs_filtered (paddress (gdbarch, addr), stream); + want_space = 1; + } /* For a pointer to char or unsigned char, also print the string pointed to, unless pointer is null. */ @@ -319,73 +333,17 @@ 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 (TYPE_TARGET_TYPE (type), NULL, addr, -1, - stream, options); - - /* Return number of characters printed, including the terminating - '\0' if we reached the end. val_print_string takes care including - the terminating '\0' if necessary. */ - return i; - } - break; - - case TYPE_CODE_REF: - elttype = check_typedef (TYPE_TARGET_TYPE (type)); - if (options->addressprint) - { - CORE_ADDR addr - = extract_typed_address (valaddr + embedded_offset, type); - - fprintf_filtered (stream, "@"); - fputs_filtered (paddress (gdbarch, addr), stream); - if (options->deref_ref) - fputs_filtered (": ", stream); - } - /* De-reference the reference. */ - if (options->deref_ref) - { - if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF) { - struct value *deref_val; - - deref_val = coerce_ref_if_computed (original_value); - if (deref_val != NULL) - { - /* More complicated computed references are not supported. */ - gdb_assert (embedded_offset == 0); - } - else - deref_val = value_at (TYPE_TARGET_TYPE (type), - unpack_pointer (type, - (valaddr - + embedded_offset))); - - common_val_print (deref_val, stream, recurse, - options, current_language); + if (want_space) + fputs_filtered (" ", stream); + i = val_print_string (TYPE_TARGET_TYPE (type), NULL, addr, -1, + stream, options); } - else - fputs_filtered ("???", stream); + return; } break; - case TYPE_CODE_FUNC: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - break; - } - /* FIXME, we should consider, at least for ANSI C language, eliminating - the distinction made between FUNCs and POINTERs to FUNCs. */ - fprintf_filtered (stream, "{"); - type_print (type, "", stream, -1); - fprintf_filtered (stream, "} "); - /* Try to print what function it points to, and its address. */ - print_address_demangle (gdbarch, address, stream, demangle); - break; - case TYPE_CODE_INT: - case TYPE_CODE_CHAR: if (options->format || options->output_format) { struct value_print_options opts = *options; @@ -402,7 +360,7 @@ f_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 (TYPE_LENGTH (type) == 1 || TYPE_CODE (type) == TYPE_CODE_CHAR) + if (TYPE_LENGTH (type) == 1) { LONGEST c; @@ -413,84 +371,6 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, } break; - case TYPE_CODE_FLAGS: - if (options->format) - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - else - val_print_type_code_flags (type, valaddr + embedded_offset, stream); - break; - - case TYPE_CODE_FLT: - if (options->format) - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - else - print_floating (valaddr + embedded_offset, type, stream); - break; - - case TYPE_CODE_VOID: - fprintf_filtered (stream, "VOID"); - break; - - case TYPE_CODE_ERROR: - fprintf_filtered (stream, "%s", TYPE_ERROR_NAME (type)); - break; - - case TYPE_CODE_RANGE: - /* FIXME, we should not ever have to print one of these yet. */ - fprintf_filtered (stream, ""); - break; - - case TYPE_CODE_BOOL: - if (options->format || options->output_format) - { - struct value_print_options opts = *options; - - opts.format = (options->format ? options->format - : options->output_format); - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, &opts, 0, stream); - } - else - { - val = extract_unsigned_integer (valaddr + embedded_offset, - TYPE_LENGTH (type), byte_order); - if (val == 0) - fprintf_filtered (stream, ".FALSE."); - else if (val == 1) - fprintf_filtered (stream, ".TRUE."); - else - /* Not a legitimate logical type, print as an integer. */ - { - /* Bash the type code temporarily. */ - TYPE_CODE (type) = TYPE_CODE_INT; - val_print (type, valaddr, embedded_offset, - address, stream, recurse, - original_value, options, current_language); - /* Restore the type code so later uses work as intended. */ - TYPE_CODE (type) = TYPE_CODE_BOOL; - } - } - break; - - case TYPE_CODE_COMPLEX: - type = TYPE_TARGET_TYPE (type); - fputs_filtered ("(", stream); - print_floating (valaddr + embedded_offset, type, stream); - fputs_filtered (",", stream); - print_floating (valaddr + embedded_offset + TYPE_LENGTH (type), - type, stream); - fputs_filtered (")", stream); - break; - - case TYPE_CODE_UNDEF: - /* This happens (without TYPE_FLAG_STUB set) on systems which don't use - dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar" - and no complete type for struct foo in that file. */ - fprintf_filtered (stream, ""); - break; - case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: /* Starting from the Fortran 90 standard, Fortran supports derived @@ -510,29 +390,78 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, fprintf_filtered (stream, " )"); break; + case TYPE_CODE_REF: + case TYPE_CODE_FUNC: + case TYPE_CODE_FLAGS: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_RANGE: + case TYPE_CODE_UNDEF: + case TYPE_CODE_COMPLEX: + case TYPE_CODE_BOOL: + case TYPE_CODE_CHAR: default: - error (_("Invalid F77 type code %d in symbol table."), TYPE_CODE (type)); + generic_val_print (type, valaddr, embedded_offset, address, + stream, recurse, original_value, options, + &f_decorations); + break; } gdb_flush (stream); - return 0; } static void -list_all_visible_commons (char *funname) +info_common_command_for_block (struct block *block, const char *comname, + int *any_printed) { - 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 block_iterator iter; + struct symbol *sym; + 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 common_block *common = SYMBOL_VALUE_COMMON_BLOCK (sym); + size_t index; + + gdb_assert (SYMBOL_CLASS (sym) == LOC_COMMON_BLOCK); + + if (comname && (!SYMBOL_LINKAGE_NAME (sym) + || strcmp (comname, SYMBOL_LINKAGE_NAME (sym)) != 0)) + continue; + + if (*any_printed) + putchar_filtered ('\n'); + else + *any_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 < common->n_entries; index++) + { + struct value *val = NULL; + volatile struct gdb_exception except; + + printf_filtered ("%s = ", + SYMBOL_PRINT_NAME (common->contents[index])); + + TRY_CATCH (except, RETURN_MASK_ERROR) + { + val = value_of_variable (common->contents[index], block); + value_print (val, gdb_stdout, &opts); + } + + if (except.reason < 0) + printf_filtered ("", except.message); + putchar_filtered ('\n'); + } + } } /* This function is used to print out the values in a given COMMON @@ -542,11 +471,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 @@ -558,136 +485,31 @@ 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; - } + info_common_command_for_block (block, comname, &values_printed); + /* 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/contrib/gdb-7/gdb/fbsd-nat.c b/contrib/gdb-7/gdb/fbsd-nat.c index 6a69b39750..be7db1d01b 100644 --- a/contrib/gdb-7/gdb/fbsd-nat.c +++ b/contrib/gdb-7/gdb/fbsd-nat.c @@ -1,6 +1,6 @@ /* Native-dependent code for FreeBSD. - Copyright (C) 2002-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -55,7 +55,7 @@ fbsd_pid_to_exec_file (int pid) #endif path = xstrprintf ("/proc/%d/file", pid); - if (readlink (path, buf, MAXPATHLEN) == -1) + if (readlink (path, buf, MAXPATHLEN - 1) == -1) { xfree (buf); buf = NULL; @@ -125,14 +125,15 @@ fbsd_find_memory_regions (find_memory_region_ftype func, void *obfd) { fprintf_filtered (gdb_stdout, "Save segment, %ld bytes at %s (%c%c%c)\n", - size, paddress (target_gdbarch, start), + size, paddress (target_gdbarch (), start), read ? 'r' : '-', write ? 'w' : '-', exec ? 'x' : '-'); } - /* Invoke the callback function to create the corefile segment. */ - func (start, size, read, write, exec, obfd); + /* Invoke the callback function to create the corefile segment. + Pass MODIFIED as true, we do not know the real modification state. */ + func (start, size, read, write, exec, 1, obfd); } do_cleanups (cleanup); @@ -142,14 +143,14 @@ fbsd_find_memory_regions (find_memory_region_ftype func, void *obfd) static int find_signalled_thread (struct thread_info *info, void *data) { - if (info->suspend.stop_signal != TARGET_SIGNAL_0 + if (info->suspend.stop_signal != GDB_SIGNAL_0 && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid)) return 1; return 0; } -static enum target_signal +static enum gdb_signal find_stop_signal (void) { struct thread_info *info = @@ -158,7 +159,7 @@ find_stop_signal (void) if (info) return info->suspend.stop_signal; else - return TARGET_SIGNAL_0; + return GDB_SIGNAL_0; } /* Create appropriate note sections for a corefile, returning them in diff --git a/contrib/gdb-7/gdb/fbsd-nat.h b/contrib/gdb-7/gdb/fbsd-nat.h index 94d35156f9..a422c46c0d 100644 --- a/contrib/gdb-7/gdb/fbsd-nat.h +++ b/contrib/gdb-7/gdb/fbsd-nat.h @@ -1,6 +1,6 @@ /* Native-dependent code for FreeBSD. - Copyright (C) 2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -29,9 +29,7 @@ extern char *fbsd_pid_to_exec_file (int pid); calling FUNC for each memory region. OBFD is passed as the last argument to FUNC. */ -extern int fbsd_find_memory_regions (int (*func) (CORE_ADDR, unsigned long, - int, int, int, void *), - void *obfd); +extern int fbsd_find_memory_regions (find_memory_region_ftype func, void *obfd); /* Create appropriate note sections for a corefile, returning them in allocated memory. */ diff --git a/contrib/gdb-7/gdb/features/btrace.dtd b/contrib/gdb-7/gdb/features/btrace.dtd new file mode 100644 index 0000000000..6fe0cd661f --- /dev/null +++ b/contrib/gdb-7/gdb/features/btrace.dtd @@ -0,0 +1,12 @@ + + + + + + + diff --git a/contrib/gdb-7/gdb/features/feature_to_c.sh b/contrib/gdb-7/gdb/features/feature_to_c.sh index e9d65df6a2..1e77cc0dc1 100644 --- a/contrib/gdb-7/gdb/features/feature_to_c.sh +++ b/contrib/gdb-7/gdb/features/feature_to_c.sh @@ -2,7 +2,7 @@ # Convert text files to compilable C arrays. # -# Copyright (C) 2007-2012 Free Software Foundation, Inc. +# Copyright (C) 2007-2013 Free Software Foundation, Inc. # # This file is part of GDB. # diff --git a/contrib/gdb-7/gdb/features/gdb-target.dtd b/contrib/gdb-7/gdb/features/gdb-target.dtd index e9fb3352d5..0900d2c2e8 100644 --- a/contrib/gdb-7/gdb/features/gdb-target.dtd +++ b/contrib/gdb-7/gdb/features/gdb-target.dtd @@ -1,4 +1,4 @@ - - + - i386:x86-64 + i386:x64-32 GNU/Linux - + diff --git a/contrib/gdb-7/gdb/features/i386/amd64-avx.c b/contrib/gdb-7/gdb/features/i386/x32-avx.c similarity index 93% copy from contrib/gdb-7/gdb/features/i386/amd64-avx.c copy to contrib/gdb-7/gdb/features/i386/x32-avx.c index 05c60ff0fe..fb7a12cd8c 100644 --- a/contrib/gdb-7/gdb/features/i386/amd64-avx.c +++ b/contrib/gdb-7/gdb/features/i386/x32-avx.c @@ -1,18 +1,20 @@ -/* THIS FILE IS GENERATED. Original: amd64-avx.xml */ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: x32-avx.xml */ #include "defs.h" #include "osabi.h" #include "target-descriptions.h" -struct target_desc *tdesc_amd64_avx; +struct target_desc *tdesc_x32_avx; static void -initialize_tdesc_amd64_avx (void) +initialize_tdesc_x32_avx (void) { struct target_desc *result = allocate_target_description (); struct tdesc_feature *feature; - struct tdesc_type *field_type, *type; + struct tdesc_type *field_type; + struct tdesc_type *type; - set_tdesc_architecture (result, bfd_scan_arch ("i386:x86-64")); + set_tdesc_architecture (result, bfd_scan_arch ("i386:x64-32")); feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core"); field_type = tdesc_create_flags (feature, "i386_eflags", 4); @@ -40,8 +42,8 @@ initialize_tdesc_amd64_avx (void) tdesc_create_reg (feature, "rdx", 3, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "rsi", 4, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "rdi", 5, 1, NULL, 64, "int64"); - tdesc_create_reg (feature, "rbp", 6, 1, NULL, 64, "data_ptr"); - tdesc_create_reg (feature, "rsp", 7, 1, NULL, 64, "data_ptr"); + tdesc_create_reg (feature, "rbp", 6, 1, NULL, 64, "int64"); + tdesc_create_reg (feature, "rsp", 7, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r8", 8, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r9", 9, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r10", 10, 1, NULL, 64, "int64"); @@ -50,7 +52,7 @@ initialize_tdesc_amd64_avx (void) tdesc_create_reg (feature, "r13", 13, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r14", 14, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r15", 15, 1, NULL, 64, "int64"); - tdesc_create_reg (feature, "rip", 16, 1, NULL, 64, "code_ptr"); + tdesc_create_reg (feature, "rip", 16, 1, NULL, 64, "uint64"); tdesc_create_reg (feature, "eflags", 17, 1, NULL, 32, "i386_eflags"); tdesc_create_reg (feature, "cs", 18, 1, NULL, 32, "int32"); tdesc_create_reg (feature, "ss", 19, 1, NULL, 32, "int32"); @@ -162,5 +164,5 @@ initialize_tdesc_amd64_avx (void) tdesc_create_reg (feature, "ymm14h", 71, 1, NULL, 128, "uint128"); tdesc_create_reg (feature, "ymm15h", 72, 1, NULL, 128, "uint128"); - tdesc_amd64_avx = result; + tdesc_x32_avx = result; } diff --git a/contrib/gdb-7/gdb/features/i386/amd64-avx.xml b/contrib/gdb-7/gdb/features/i386/x32-avx.xml similarity index 68% copy from contrib/gdb-7/gdb/features/i386/amd64-avx.xml copy to contrib/gdb-7/gdb/features/i386/x32-avx.xml index 1fa7c47f4d..78c77fa135 100644 --- a/contrib/gdb-7/gdb/features/i386/amd64-avx.xml +++ b/contrib/gdb-7/gdb/features/i386/x32-avx.xml @@ -1,16 +1,16 @@ - - + - i386:x86-64 - + i386:x64-32 + diff --git a/contrib/gdb-7/gdb/features/i386/64bit-core.xml b/contrib/gdb-7/gdb/features/i386/x32-core.xml similarity index 93% copy from contrib/gdb-7/gdb/features/i386/64bit-core.xml copy to contrib/gdb-7/gdb/features/i386/x32-core.xml index 6dd6cdbd5f..dc420ace3f 100644 --- a/contrib/gdb-7/gdb/features/i386/64bit-core.xml +++ b/contrib/gdb-7/gdb/features/i386/x32-core.xml @@ -1,5 +1,5 @@ - - + - i386:x86-64 + i386:x64-32 GNU/Linux - + diff --git a/contrib/gdb-7/gdb/features/i386/amd64.c b/contrib/gdb-7/gdb/features/i386/x32.c similarity index 93% copy from contrib/gdb-7/gdb/features/i386/amd64.c copy to contrib/gdb-7/gdb/features/i386/x32.c index 154e8df129..34e5087f6d 100644 --- a/contrib/gdb-7/gdb/features/i386/amd64.c +++ b/contrib/gdb-7/gdb/features/i386/x32.c @@ -1,18 +1,20 @@ -/* THIS FILE IS GENERATED. Original: amd64.xml */ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: x32.xml */ #include "defs.h" #include "osabi.h" #include "target-descriptions.h" -struct target_desc *tdesc_amd64; +struct target_desc *tdesc_x32; static void -initialize_tdesc_amd64 (void) +initialize_tdesc_x32 (void) { struct target_desc *result = allocate_target_description (); struct tdesc_feature *feature; - struct tdesc_type *field_type, *type; + struct tdesc_type *field_type; + struct tdesc_type *type; - set_tdesc_architecture (result, bfd_scan_arch ("i386:x86-64")); + set_tdesc_architecture (result, bfd_scan_arch ("i386:x64-32")); feature = tdesc_create_feature (result, "org.gnu.gdb.i386.core"); field_type = tdesc_create_flags (feature, "i386_eflags", 4); @@ -40,8 +42,8 @@ initialize_tdesc_amd64 (void) tdesc_create_reg (feature, "rdx", 3, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "rsi", 4, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "rdi", 5, 1, NULL, 64, "int64"); - tdesc_create_reg (feature, "rbp", 6, 1, NULL, 64, "data_ptr"); - tdesc_create_reg (feature, "rsp", 7, 1, NULL, 64, "data_ptr"); + tdesc_create_reg (feature, "rbp", 6, 1, NULL, 64, "int64"); + tdesc_create_reg (feature, "rsp", 7, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r8", 8, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r9", 9, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r10", 10, 1, NULL, 64, "int64"); @@ -50,7 +52,7 @@ initialize_tdesc_amd64 (void) tdesc_create_reg (feature, "r13", 13, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r14", 14, 1, NULL, 64, "int64"); tdesc_create_reg (feature, "r15", 15, 1, NULL, 64, "int64"); - tdesc_create_reg (feature, "rip", 16, 1, NULL, 64, "code_ptr"); + tdesc_create_reg (feature, "rip", 16, 1, NULL, 64, "uint64"); tdesc_create_reg (feature, "eflags", 17, 1, NULL, 32, "i386_eflags"); tdesc_create_reg (feature, "cs", 18, 1, NULL, 32, "int32"); tdesc_create_reg (feature, "ss", 19, 1, NULL, 32, "int32"); @@ -144,5 +146,5 @@ initialize_tdesc_amd64 (void) tdesc_create_reg (feature, "xmm15", 55, 1, NULL, 128, "vec128"); tdesc_create_reg (feature, "mxcsr", 56, 1, "vector", 32, "i386_mxcsr"); - tdesc_amd64 = result; + tdesc_x32 = result; } diff --git a/contrib/gdb-7/gdb/features/i386/amd64.xml b/contrib/gdb-7/gdb/features/i386/x32.xml similarity index 67% copy from contrib/gdb-7/gdb/features/i386/amd64.xml copy to contrib/gdb-7/gdb/features/i386/x32.xml index b6077c002b..4405006a75 100644 --- a/contrib/gdb-7/gdb/features/i386/amd64.xml +++ b/contrib/gdb-7/gdb/features/i386/x32.xml @@ -1,15 +1,15 @@ - - + - i386:x86-64 - + i386:x64-32 + diff --git a/contrib/gdb-7/gdb/features/library-list-svr4.dtd b/contrib/gdb-7/gdb/features/library-list-svr4.dtd index 93bc83f49d..cae7fd89f3 100644 --- a/contrib/gdb-7/gdb/features/library-list-svr4.dtd +++ b/contrib/gdb-7/gdb/features/library-list-svr4.dtd @@ -1,4 +1,4 @@ - insert a regular wp. -break-watch -r --> insert a read watchpoint. - -break-watch -a --> insert an access wp. */ + -break-watch -a --> insert an access wp. */ void mi_cmd_break_watch (char *command, char **argv, int argc) @@ -228,13 +249,13 @@ mi_cmd_break_watch (char *command, char **argv, int argc) }; /* Parse arguments. */ - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; while (1) { int opt = mi_getopt ("-break-watch", argc, argv, - opts, &optind, &optarg); + opts, &oind, &oarg); if (opt < 0) break; @@ -248,13 +269,13 @@ mi_cmd_break_watch (char *command, char **argv, int argc) break; } } - if (optind >= argc) + if (oind >= argc) error (_("-break-watch: Missing ")); - if (optind < argc - 1) + if (oind < argc - 1) error (_("-break-watch: Garbage following ")); - expr = argv[optind]; + expr = argv[oind]; - /* Now we have what we need, let's insert the watchpoint! */ + /* Now we have what we need, let's insert the watchpoint! */ switch (type) { case REG_WP: diff --git a/contrib/gdb-7/gdb/tui/tui-command.h b/contrib/gdb-7/gdb/mi/mi-cmd-break.h similarity index 67% copy from contrib/gdb-7/gdb/tui/tui-command.h copy to contrib/gdb-7/gdb/mi/mi-cmd-break.h index 1b3fcb6f5d..e58ae7068a 100644 --- a/contrib/gdb-7/gdb/tui/tui-command.h +++ b/contrib/gdb-7/gdb/mi/mi-cmd-break.h @@ -1,9 +1,7 @@ -/* Specific command window processing. +/* MI Command Set - breakpoint and watchpoint commands. + Copyright (C) 2012-2013 Free Software Foundation, Inc. - Copyright (C) 1998-2001, 2004, 2007-2012 Free Software Foundation, - Inc. - - Contributed by Hewlett-Packard Company. + Contributed by Intel Corporation. This file is part of GDB. @@ -20,9 +18,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef TUI_COMMAND_H -#define TUI_COMMAND_H +#ifndef MI_CMD_BREAK_H +#define MI_CMD_BREAK_H + -extern unsigned int tui_dispatch_ctrl_char (unsigned int); +/* Setup the reporting of the insertion of a new breakpoint or + catchpoint. */ +struct cleanup *setup_breakpoint_reporting (void); #endif + diff --git a/contrib/gdb-7/gdb/mi/mi-cmd-catch.c b/contrib/gdb-7/gdb/mi/mi-cmd-catch.c new file mode 100644 index 0000000000..cd932fe999 --- /dev/null +++ b/contrib/gdb-7/gdb/mi/mi-cmd-catch.c @@ -0,0 +1,101 @@ +/* MI Command Set - catch commands. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + + Contributed by Intel Corporation. + + 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 "arch-utils.h" +#include "breakpoint.h" +#include "gdb.h" +#include "libiberty.h" +#include "mi-cmds.h" +#include "mi-getopt.h" +#include "mi-cmd-break.h" + + +/* Common path for the -catch-load and -catch-unload. */ + +static void +mi_catch_load_unload (int load, char *argv[], int argc) +{ + struct cleanup *back_to; + const char *actual_cmd = load ? "-catch-load" : "-catch-unload"; + int temp = 0; + int enabled = 1; + int oind = 0; + char *oarg; + enum opt + { + OPT_TEMP, + OPT_DISABLED, + }; + static const struct mi_opt opts[] = + { + { "t", OPT_TEMP, 0 }, + { "d", OPT_DISABLED, 0 }, + { 0, 0, 0 } + }; + + for (;;) + { + int opt = mi_getopt (actual_cmd, argc, argv, opts, + &oind, &oarg); + + if (opt < 0) + break; + + switch ((enum opt) opt) + { + case OPT_TEMP: + temp = 1; + break; + case OPT_DISABLED: + enabled = 0; + break; + } + } + + if (oind >= argc) + error (_("-catch-load/unload: Missing ")); + if (oind < argc -1) + error (_("-catch-load/unload: Garbage following the ")); + + back_to = setup_breakpoint_reporting (); + + add_solib_catchpoint (argv[oind], load, temp, enabled); + + do_cleanups (back_to); +} + +/* Handler for the -catch-load. */ + +void +mi_cmd_catch_load (char *cmd, char *argv[], int argc) +{ + mi_catch_load_unload (1, argv, argc); +} + + +/* Handler for the -catch-unload. */ + +void +mi_cmd_catch_unload (char *cmd, char *argv[], int argc) +{ + mi_catch_load_unload (0, argv, argc); +} + diff --git a/contrib/gdb-7/gdb/mi/mi-cmd-disas.c b/contrib/gdb-7/gdb/mi/mi-cmd-disas.c index 6de7c5f6c9..1519f086cd 100644 --- a/contrib/gdb-7/gdb/mi/mi-cmd-disas.c +++ b/contrib/gdb-7/gdb/mi/mi-cmd-disas.c @@ -1,5 +1,5 @@ /* MI Command Set - disassemble commands. - Copyright (C) 2000-2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. @@ -27,8 +27,7 @@ #include "ui-out.h" #include "disasm.h" -/* The arguments to be passed on the command line and parsed here are: - +/* The arguments to be passed on the command line and parsed here are either: START-ADDRESS: address to start the disassembly at. @@ -50,6 +49,7 @@ 2 -- disassembly and opcodes. 3 -- disassembly, source and opcodes. */ + void mi_cmd_disassemble (char *command, char **argv, int argc) { @@ -75,60 +75,61 @@ mi_cmd_disassemble (char *command, char **argv, int argc) CORE_ADDR high = 0; struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); - /* Options processing stuff. */ - int optind = 0; - char *optarg; + /* Options processing stuff. */ + int oind = 0; + char *oarg; enum opt { FILE_OPT, LINE_OPT, NUM_OPT, START_OPT, END_OPT }; - static const struct mi_opt opts[] = { - {"f", FILE_OPT, 1}, - {"l", LINE_OPT, 1}, - {"n", NUM_OPT, 1}, - {"s", START_OPT, 1}, - {"e", END_OPT, 1}, - { 0, 0, 0 } - }; + static const struct mi_opt opts[] = + { + {"f", FILE_OPT, 1}, + {"l", LINE_OPT, 1}, + {"n", NUM_OPT, 1}, + {"s", START_OPT, 1}, + {"e", END_OPT, 1}, + { 0, 0, 0 } + }; /* Get the options with their arguments. Keep track of what we - encountered. */ + encountered. */ while (1) { int opt = mi_getopt ("-data-disassemble", argc, argv, opts, - &optind, &optarg); + &oind, &oarg); if (opt < 0) break; switch ((enum opt) opt) { case FILE_OPT: - file_string = xstrdup (optarg); + file_string = xstrdup (oarg); file_seen = 1; make_cleanup (xfree, file_string); break; case LINE_OPT: - line_num = atoi (optarg); + line_num = atoi (oarg); line_seen = 1; break; case NUM_OPT: - how_many = atoi (optarg); + how_many = atoi (oarg); num_seen = 1; break; case START_OPT: - low = parse_and_eval_address (optarg); + low = parse_and_eval_address (oarg); start_seen = 1; break; case END_OPT: - high = parse_and_eval_address (optarg); + high = parse_and_eval_address (oarg); end_seen = 1; break; } } - argv += optind; - argc -= optind; + argv += oind; + argc -= oind; /* Allow only filename + linenum (with how_many which is not - required) OR start_addr + and_addr */ + required) OR start_addr + end_addr. */ if (!((line_seen && file_seen && num_seen && !start_seen && !end_seen) || (line_seen && file_seen && !num_seen && !start_seen && !end_seen) @@ -144,7 +145,7 @@ mi_cmd_disassemble (char *command, char **argv, int argc) if (mode < 0 || mode > 3) error (_("-data-disassemble: Mode argument must be 0, 1, 2, or 3.")); - /* Convert the mode into a set of disassembly flags */ + /* Convert the mode into a set of disassembly flags. */ disasm_flags = 0; if (mode & 0x1) @@ -153,7 +154,7 @@ mi_cmd_disassemble (char *command, char **argv, int argc) disasm_flags |= DISASSEMBLY_RAW_INSN; /* We must get the function beginning and end where line_num is - contained. */ + contained. */ if (line_seen && file_seen) { diff --git a/contrib/gdb-7/gdb/mi/mi-cmd-env.c b/contrib/gdb-7/gdb/mi/mi-cmd-env.c index 65307a69ed..e69062b125 100644 --- a/contrib/gdb-7/gdb/mi/mi-cmd-env.c +++ b/contrib/gdb-7/gdb/mi/mi-cmd-env.c @@ -1,6 +1,5 @@ /* MI Command Set - environment commands. - - Copyright (C) 2002-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. Contributed by Red Hat Inc. @@ -36,6 +35,7 @@ #include "gdb_stat.h" static void env_mod_path (char *dirname, char **which_path); + extern void _initialize_mi_cmd_env (void); static const char path_var_name[] = "PATH"; @@ -44,6 +44,7 @@ static char *orig_path = NULL; /* The following is copied from mi-main.c so for m1 and below we can perform old behavior and use cli commands. If ARGS is non-null, append it to the CMD. */ + static void env_execute_cli_command (const char *cmd, const char *args) { @@ -63,15 +64,15 @@ env_execute_cli_command (const char *cmd, const char *args) } } - /* Print working directory. */ + void mi_cmd_env_pwd (char *command, char **argv, int argc) { struct ui_out *uiout = current_uiout; if (argc > 0) - error (_("-environment-pwd: No arguments required")); + error (_("-environment-pwd: No arguments allowed")); if (mi_version (uiout) < 2) { @@ -89,6 +90,7 @@ mi_cmd_env_pwd (char *command, char **argv, int argc) } /* Change working directory. */ + void mi_cmd_env_cd (char *command, char **argv, int argc) { @@ -110,6 +112,7 @@ env_mod_path (char *dirname, char **which_path) } /* Add one or more directories to start of executable search path. */ + void mi_cmd_env_path (char *command, char **argv, int argc) { @@ -117,9 +120,9 @@ mi_cmd_env_path (char *command, char **argv, int argc) char *exec_path; char *env; int reset = 0; - int optind = 0; + int oind = 0; int i; - char *optarg; + char *oarg; enum opt { RESET_OPT @@ -143,7 +146,7 @@ mi_cmd_env_path (char *command, char **argv, int argc) while (1) { int opt = mi_getopt ("-environment-path", argc, argv, opts, - &optind, &optarg); + &oind, &oarg); if (opt < 0) break; @@ -154,8 +157,8 @@ mi_cmd_env_path (char *command, char **argv, int argc) break; } } - argv += optind; - argc -= optind; + argv += oind; + argc -= oind; if (reset) @@ -184,14 +187,15 @@ mi_cmd_env_path (char *command, char **argv, int argc) } /* Add zero or more directories to the front of the source path. */ + void mi_cmd_env_dir (char *command, char **argv, int argc) { struct ui_out *uiout = current_uiout; int i; - int optind = 0; + int oind = 0; int reset = 0; - char *optarg; + char *oarg; enum opt { RESET_OPT @@ -215,7 +219,7 @@ mi_cmd_env_dir (char *command, char **argv, int argc) while (1) { int opt = mi_getopt ("-environment-directory", argc, argv, opts, - &optind, &optarg); + &oind, &oarg); if (opt < 0) break; @@ -226,8 +230,8 @@ mi_cmd_env_dir (char *command, char **argv, int argc) break; } } - argv += optind; - argc -= optind; + argv += oind; + argc -= oind; if (reset) { @@ -244,13 +248,15 @@ mi_cmd_env_dir (char *command, char **argv, int argc) } /* Set the inferior terminal device name. */ + void mi_cmd_inferior_tty_set (char *command, char **argv, int argc) { set_inferior_io_terminal (argv[0]); } -/* Print the inferior terminal device name */ +/* Print the inferior terminal device name. */ + void mi_cmd_inferior_tty_show (char *command, char **argv, int argc) { @@ -273,7 +279,7 @@ _initialize_mi_cmd_env (void) /* We want original execution path to reset to, if desired later. At this point, current inferior is not created, so cannot use current_inferior ()->environment. Also, there's no obvious - place where this code can be moved suchs that it surely run + place where this code can be moved such that it surely run before any code possibly mangles original PATH. */ environment = make_environ (); init_environ (environment); diff --git a/contrib/gdb-7/gdb/mi/mi-cmd-file.c b/contrib/gdb-7/gdb/mi/mi-cmd-file.c index c4d1461917..07d972289c 100644 --- a/contrib/gdb-7/gdb/mi/mi-cmd-file.c +++ b/contrib/gdb-7/gdb/mi/mi-cmd-file.c @@ -1,5 +1,5 @@ -/* MI Command Set - breakpoint and watchpoint commands. - Copyright (C) 2000-2002, 2007-2012 Free Software Foundation, Inc. +/* MI Command Set - file commands. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. @@ -27,7 +27,7 @@ #include "psymtab.h" /* Return to the client the absolute path and line number of the - current file being executed. */ + current file being executed. */ void mi_cmd_file_list_exec_source_file (char *command, char **argv, int argc) @@ -38,31 +38,28 @@ mi_cmd_file_list_exec_source_file (char *command, char **argv, int argc) if (!mi_valid_noargs ("-file-list-exec-source-file", argc, argv)) error (_("-file-list-exec-source-file: Usage: No args")); - /* Set the default file and line, also get them */ + /* Set the default file and line, also get them. */ set_default_source_symtab_and_line (); st = get_current_source_symtab_and_line (); - /* We should always get a symtab. - Apparently, filename does not need to be tested for NULL. - The documentation in symtab.h suggests it will always be correct */ + /* We should always get a symtab. Apparently, filename does not + need to be tested for NULL. The documentation in symtab.h + suggests it will always be correct. */ if (!st.symtab) error (_("-file-list-exec-source-file: No symtab")); - /* Extract the fullname if it is not known yet */ - symtab_to_fullname (st.symtab); - - /* Print to the user the line, filename and fullname */ + /* Print to the user the line, filename and fullname. */ ui_out_field_int (uiout, "line", st.line); - ui_out_field_string (uiout, "file", st.symtab->filename); + ui_out_field_string (uiout, "file", + symtab_to_filename_for_display (st.symtab)); - /* We may not be able to open the file (not available). */ - if (st.symtab->fullname) - ui_out_field_string (uiout, "fullname", st.symtab->fullname); + ui_out_field_string (uiout, "fullname", symtab_to_fullname (st.symtab)); ui_out_field_int (uiout, "macro-info", st.symtab->macro_table ? 1 : 0); } /* A callback for map_partial_symbol_filenames. */ + static void print_partial_file_name (const char *filename, const char *fullname, void *ignore) @@ -89,21 +86,16 @@ mi_cmd_file_list_exec_source_files (char *command, char **argv, int argc) if (!mi_valid_noargs ("-file-list-exec-source-files", argc, argv)) error (_("-file-list-exec-source-files: Usage: No args")); - /* Print the table header */ + /* Print the table header. */ ui_out_begin (uiout, ui_out_type_list, "files"); - /* Look at all of the symtabs */ + /* Look at all of the symtabs. */ ALL_SYMTABS (objfile, s) { ui_out_begin (uiout, ui_out_type_tuple, NULL); - ui_out_field_string (uiout, "file", s->filename); - - /* Extract the fullname if it is not known yet */ - symtab_to_fullname (s); - - if (s->fullname) - ui_out_field_string (uiout, "fullname", s->fullname); + ui_out_field_string (uiout, "file", symtab_to_filename_for_display (s)); + ui_out_field_string (uiout, "fullname", symtab_to_fullname (s)); ui_out_end (uiout, ui_out_type_tuple); } diff --git a/contrib/gdb-7/gdb/gdb.c b/contrib/gdb-7/gdb/mi/mi-cmd-info.c similarity index 62% copy from contrib/gdb-7/gdb/gdb.c copy to contrib/gdb-7/gdb/mi/mi-cmd-info.c index e1dcdc605c..8eb4220963 100644 --- a/contrib/gdb-7/gdb/gdb.c +++ b/contrib/gdb-7/gdb/mi/mi-cmd-info.c @@ -1,5 +1,5 @@ -/* Main function for CLI gdb. - Copyright (C) 2002, 2007-2012 Free Software Foundation, Inc. +/* MI Command Set - information commands. + Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,19 +17,22 @@ along with this program. If not, see . */ #include "defs.h" -#include "main.h" -#include "gdb_string.h" -#include "interps.h" +#include "osdata.h" +#include "mi-cmds.h" -int -main (int argc, char **argv) +void +mi_cmd_info_os (char *command, char **argv, int argc) { - struct captured_main_args args; - - memset (&args, 0, sizeof args); - args.argc = argc; - args.argv = argv; - args.use_windows = 0; - args.interpreter_p = INTERP_CONSOLE; - return gdb_main (&args); + switch (argc) + { + case 0: + info_osdata_command ("", 0); + break; + case 1: + info_osdata_command (argv[0], 0); + break; + default: + error (_("Usage: -info-os [INFOTYPE]")); + break; + } } diff --git a/contrib/gdb-7/gdb/mi/mi-cmd-stack.c b/contrib/gdb-7/gdb/mi/mi-cmd-stack.c index c0c17bce9a..ee0ccaa1ff 100644 --- a/contrib/gdb-7/gdb/mi/mi-cmd-stack.c +++ b/contrib/gdb-7/gdb/mi/mi-cmd-stack.c @@ -1,6 +1,5 @@ /* MI Command Set - stack commands. - Copyright (C) 2000, 2002-2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. @@ -39,11 +38,12 @@ static void list_args_or_locals (enum what_to_list what, enum print_values values, struct frame_info *fi); -/* Print a list of the stack frames. Args can be none, in which case +/* Print a list of the stack frames. Args can be none, in which case we want to print the whole backtrace, or a pair of numbers specifying the frame numbers at which to start and stop the - display. If the two numbers are equal, a single frame will be - displayed. */ + display. If the two numbers are equal, a single frame will be + displayed. */ + void mi_cmd_stack_list_frames (char *command, char **argv, int argc) { @@ -64,14 +64,14 @@ mi_cmd_stack_list_frames (char *command, char **argv, int argc) else { /* Called with no arguments, it means we want the whole - backtrace. */ + backtrace. */ frame_low = -1; frame_high = -1; } /* Let's position fi on the frame at which to start the display. Could be the innermost frame if the whole stack needs - displaying, or if frame_low is 0. */ + displaying, or if frame_low is 0. */ for (i = 0, fi = get_current_frame (); fi && i < frame_low; i++, fi = get_prev_frame (fi)); @@ -81,15 +81,15 @@ mi_cmd_stack_list_frames (char *command, char **argv, int argc) cleanup_stack = make_cleanup_ui_out_list_begin_end (current_uiout, "stack"); - /* Now let;s print the frames up to frame_high, or until there are - frames in the stack. */ + /* Now let's print the frames up to frame_high, or until there are + frames in the stack. */ for (; fi && (i <= frame_high || frame_high == -1); i++, fi = get_prev_frame (fi)) { QUIT; /* Print the location and the address always, even for level 0. - args == 0: don't print the arguments. */ + If args is 0, don't print the arguments. */ print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */ ); } @@ -110,7 +110,7 @@ mi_cmd_stack_info_depth (char *command, char **argv, int argc) frame_high = atoi (argv[0]); else /* Called with no arguments, it means we want the real depth of - the stack. */ + the stack. */ frame_high = -1; for (i = 0, fi = get_current_frame (); @@ -141,7 +141,8 @@ parse_print_values (char *name) /* Print a list of the locals for the current frame. With argument of 0, print only the names, with argument of 1 print also the - values. */ + values. */ + void mi_cmd_stack_list_locals (char *command, char **argv, int argc) { @@ -157,7 +158,8 @@ mi_cmd_stack_list_locals (char *command, char **argv, int argc) /* Print a list of the arguments for the current frame. With argument of 0, print only the names, with argument of 1 print also the - values. */ + values. */ + void mi_cmd_stack_list_args (char *command, char **argv, int argc) { @@ -181,7 +183,7 @@ mi_cmd_stack_list_args (char *command, char **argv, int argc) else { /* Called with no arguments, it means we want args for the whole - backtrace. */ + backtrace. */ frame_low = -1; frame_high = -1; } @@ -190,7 +192,7 @@ mi_cmd_stack_list_args (char *command, char **argv, int argc) /* Let's position fi on the frame at which to start the display. Could be the innermost frame if the whole stack needs - displaying, or if frame_low is 0. */ + displaying, or if frame_low is 0. */ for (i = 0, fi = get_current_frame (); fi && i < frame_low; i++, fi = get_prev_frame (fi)); @@ -202,7 +204,7 @@ mi_cmd_stack_list_args (char *command, char **argv, int argc) = make_cleanup_ui_out_list_begin_end (uiout, "stack-args"); /* Now let's print the frames up to frame_high, or until there are - frames in the stack. */ + frames in the stack. */ for (; fi && (i <= frame_high || frame_high == -1); i++, fi = get_prev_frame (fi)) @@ -223,6 +225,7 @@ mi_cmd_stack_list_args (char *command, char **argv, int argc) current frame. ARGC must be 1 and ARGV[0] specify if only the names, or both names and values of the variables must be printed. See parse_print_value for possible values. */ + void mi_cmd_stack_list_variables (char *command, char **argv, int argc) { @@ -236,19 +239,23 @@ mi_cmd_stack_list_variables (char *command, char **argv, int argc) list_args_or_locals (all, parse_print_values (argv[0]), frame); } -/* Print single local or argument. ARG must be already read in. For WHAT and - VALUES see list_args_or_locals. +/* Print single local or argument. ARG must be already read in. For + WHAT and VALUES see list_args_or_locals. - Errors are printed as if they would be the parameter value. Use zeroed ARG - iff it should not be printed accoring to VALUES. */ + Errors are printed as if they would be the parameter value. Use + zeroed ARG iff it should not be printed according to VALUES. */ static void list_arg_or_local (const struct frame_arg *arg, enum what_to_list what, enum print_values values) { + struct cleanup *old_chain; struct cleanup *cleanup_tuple = NULL; struct ui_out *uiout = current_uiout; - struct ui_stream *stb = ui_out_stream_new (uiout); + struct ui_file *stb; + + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); gdb_assert (!arg->val || !arg->error); gdb_assert ((values == PRINT_NO_VALUES && arg->val == NULL @@ -263,9 +270,9 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what, if (values != PRINT_NO_VALUES || what == all) cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - fputs_filtered (SYMBOL_PRINT_NAME (arg->sym), stb->stream); + fputs_filtered (SYMBOL_PRINT_NAME (arg->sym), stb); if (arg->entry_kind == print_entry_values_only) - fputs_filtered ("@entry", stb->stream); + fputs_filtered ("@entry", stb); ui_out_field_stream (uiout, "name", stb); if (what == all && SYMBOL_IS_ARGUMENT (arg->sym)) @@ -274,7 +281,7 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what, if (values == PRINT_SIMPLE_VALUES) { check_typedef (arg->sym->type); - type_print (arg->sym->type, "", stb->stream, -1); + type_print (arg->sym->type, "", stb, -1); ui_out_field_stream (uiout, "type", stb); } @@ -294,40 +301,38 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what, get_raw_print_options (&opts); opts.deref_ref = 1; - common_val_print (arg->val, stb->stream, 0, &opts, + common_val_print (arg->val, stb, 0, &opts, language_def (SYMBOL_LANGUAGE (arg->sym))); } } if (except.message) - fprintf_filtered (stb->stream, _(""), + fprintf_filtered (stb, _(""), except.message); ui_out_field_stream (uiout, "value", stb); } - ui_out_stream_delete (stb); if (values != PRINT_NO_VALUES || what == all) do_cleanups (cleanup_tuple); + do_cleanups (old_chain); } /* Print a list of the locals or the arguments for the currently selected frame. If the argument passed is 0, printonly the names of the variables, if an argument of 1 is passed, print the values - as well. */ + as well. */ + static void list_args_or_locals (enum what_to_list what, enum print_values values, struct frame_info *fi) { struct block *block; struct symbol *sym; - struct dict_iterator iter; + struct block_iterator iter; struct cleanup *cleanup_list; - struct ui_stream *stb; struct type *type; char *name_of_result; struct ui_out *uiout = current_uiout; - stb = ui_out_stream_new (uiout); - block = get_frame_block (fi, 0); switch (what) @@ -389,11 +394,12 @@ list_args_or_locals (enum what_to_list what, enum print_values values, struct frame_arg arg, entryarg; if (SYMBOL_IS_ARGUMENT (sym)) - sym2 = lookup_symbol (SYMBOL_NATURAL_NAME (sym), + sym2 = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), block, VAR_DOMAIN, - (int *) NULL); + NULL); else sym2 = sym; + gdb_assert (sym2 != NULL); memset (&arg, 0, sizeof (arg)); arg.sym = sym2; @@ -411,7 +417,10 @@ list_args_or_locals (enum what_to_list what, enum print_values values, && TYPE_CODE (type) != TYPE_CODE_UNION) { case PRINT_ALL_VALUES: - read_frame_arg (sym2, fi, &arg, &entryarg); + if (SYMBOL_IS_ARGUMENT (sym)) + read_frame_arg (sym2, fi, &arg, &entryarg); + else + read_frame_local (sym2, fi, &arg); } break; } @@ -424,13 +433,13 @@ list_args_or_locals (enum what_to_list what, enum print_values values, xfree (entryarg.error); } } + if (BLOCK_FUNCTION (block)) break; else block = BLOCK_SUPERBLOCK (block); } do_cleanups (cleanup_list); - ui_out_stream_delete (stb); } void @@ -446,7 +455,7 @@ void mi_cmd_stack_info_frame (char *command, char **argv, int argc) { if (argc > 0) - error (_("-stack-info-frame: No arguments required")); + error (_("-stack-info-frame: No arguments allowed")); print_frame_info (get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 0); } diff --git a/contrib/gdb-7/gdb/mi/mi-cmd-target.c b/contrib/gdb-7/gdb/mi/mi-cmd-target.c index edeedaf527..67a43355d8 100644 --- a/contrib/gdb-7/gdb/mi/mi-cmd-target.c +++ b/contrib/gdb-7/gdb/mi/mi-cmd-target.c @@ -1,5 +1,5 @@ /* MI Command Set - target commands. - Copyright (C) 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2007-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -26,21 +26,21 @@ void mi_cmd_target_file_get (char *command, char **argv, int argc) { - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; const char *remote_file, *local_file; static const struct mi_opt opts[] = - { - { 0, 0, 0 } - }; + { + { 0, 0, 0 } + }; static const char prefix[] = "-target-file-get"; - if (mi_getopt (prefix, argc, argv, opts, &optind, &optarg) != -1 - || optind != argc - 2) + if (mi_getopt (prefix, argc, argv, opts, &oind, &oarg) != -1 + || oind != argc - 2) error (_("-target-file-get: Usage: REMOTE_FILE LOCAL_FILE")); - remote_file = argv[optind]; - local_file = argv[optind + 1]; + remote_file = argv[oind]; + local_file = argv[oind + 1]; remote_file_get (remote_file, local_file, 0); } @@ -50,21 +50,21 @@ mi_cmd_target_file_get (char *command, char **argv, int argc) void mi_cmd_target_file_put (char *command, char **argv, int argc) { - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; const char *remote_file, *local_file; static const struct mi_opt opts[] = - { - { 0, 0, 0 } - }; + { + { 0, 0, 0 } + }; static const char prefix[] = "-target-file-put"; - if (mi_getopt (prefix, argc, argv, opts, &optind, &optarg) != -1 - || optind != argc - 2) + if (mi_getopt (prefix, argc, argv, opts, &oind, &oarg) != -1 + || oind != argc - 2) error (_("-target-file-put: Usage: LOCAL_FILE REMOTE_FILE")); - local_file = argv[optind]; - remote_file = argv[optind + 1]; + local_file = argv[oind]; + remote_file = argv[oind + 1]; remote_file_put (local_file, remote_file, 0); } @@ -74,20 +74,20 @@ mi_cmd_target_file_put (char *command, char **argv, int argc) void mi_cmd_target_file_delete (char *command, char **argv, int argc) { - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; const char *remote_file; static const struct mi_opt opts[] = - { - { 0, 0, 0 } - }; + { + { 0, 0, 0 } + }; static const char prefix[] = "-target-file-delete"; - if (mi_getopt (prefix, argc, argv, opts, &optind, &optarg) != -1 - || optind != argc - 1) + if (mi_getopt (prefix, argc, argv, opts, &oind, &oarg) != -1 + || oind != argc - 1) error (_("-target-file-delete: Usage: REMOTE_FILE")); - remote_file = argv[optind]; + remote_file = argv[oind]; remote_file_delete (remote_file, 0); } diff --git a/contrib/gdb-7/gdb/mi/mi-cmd-var.c b/contrib/gdb-7/gdb/mi/mi-cmd-var.c index 1bc7144a76..558454e704 100644 --- a/contrib/gdb-7/gdb/mi/mi-cmd-var.c +++ b/contrib/gdb-7/gdb/mi/mi-cmd-var.c @@ -1,7 +1,5 @@ /* MI Command Set - varobj commands. - - Copyright (C) 2000, 2002, 2004-2005, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -22,6 +20,7 @@ #include "defs.h" #include "mi-cmds.h" +#include "mi-main.h" #include "ui-out.h" #include "mi-out.h" #include "varobj.h" @@ -35,11 +34,11 @@ const char mi_no_values[] = "--no-values"; const char mi_simple_values[] = "--simple-values"; const char mi_all_values[] = "--all-values"; -extern int varobjdebug; /* defined in varobj.c. */ +extern unsigned int varobjdebug; /* defined in varobj.c. */ static void varobj_update_one (struct varobj *var, - enum print_values print_values, - int explicit); + enum print_values print_values, + int explicit); static int mi_print_value_p (struct varobj *var, enum print_values print_values); @@ -47,6 +46,7 @@ static int mi_print_value_p (struct varobj *var, /* Print variable object VAR. The PRINT_VALUES parameter controls if the value should be printed. The PRINT_EXPRESSION parameter controls if the expression should be printed. */ + static void print_varobj (struct varobj *var, enum print_values print_values, int print_expression) @@ -109,15 +109,11 @@ mi_cmd_var_create (char *command, char **argv, int argc) enum varobj_type var_type; if (argc != 3) - { - /* mi_error_message = xstrprintf ("-var-create: Usage: - ...."); return MI_CMD_ERROR; */ - error (_("-var-create: Usage: NAME FRAME EXPRESSION.")); - } + error (_("-var-create: Usage: NAME FRAME EXPRESSION.")); name = xstrdup (argv[0]); - /* Add cleanup for name. Must be free_current_contents as - name can be reallocated */ + /* Add cleanup for name. Must be free_current_contents as name can + be reallocated. */ old_cleanups = make_cleanup (free_current_contents, &name); frame = xstrdup (argv[1]); @@ -175,12 +171,12 @@ mi_cmd_var_delete (char *command, char **argv, int argc) error (_("-var-delete: Usage: [-c] EXPRESSION.")); name = xstrdup (argv[0]); - /* Add cleanup for name. Must be free_current_contents as - name can be reallocated */ + /* Add cleanup for name. Must be free_current_contents as name can + be reallocated. */ old_cleanups = make_cleanup (free_current_contents, &name); /* If we have one single argument it cannot be '-c' or any string - starting with '-'. */ + starting with '-'. */ if (argc == 1) { if (strcmp (name, "-c") == 0) @@ -191,7 +187,7 @@ mi_cmd_var_delete (char *command, char **argv, int argc) } /* If we have 2 arguments they must be '-c' followed by a string - which would be the variable name. */ + which would be the variable name. */ if (argc == 2) { if (strcmp (name, "-c") != 0) @@ -203,7 +199,7 @@ mi_cmd_var_delete (char *command, char **argv, int argc) } /* If we didn't error out, now NAME contains the name of the - variable. */ + variable. */ var = varobj_get_handle (name); @@ -252,18 +248,18 @@ mi_cmd_var_set_format (char *command, char **argv, int argc) if (argc != 2) error (_("-var-set-format: Usage: NAME FORMAT.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); format = mi_parse_format (argv[1]); - /* Set the format of VAR to given format */ + /* Set the format of VAR to the given format. */ varobj_set_display_format (var, format); - /* Report the new current format */ + /* Report the new current format. */ ui_out_field_string (uiout, "format", varobj_format_string[(int) format]); - /* Report the value in the new format */ + /* Report the value in the new format. */ val = varobj_get_value (var); ui_out_field_string (uiout, "value", val); xfree (val); @@ -305,12 +301,11 @@ mi_cmd_var_set_frozen (char *command, char **argv, int argc) varobj_set_frozen (var, frozen); - /* We don't automatically return the new value, or what varobjs got new - values during unfreezing. If this information is required, client - should call -var-update explicitly. */ + /* We don't automatically return the new value, or what varobjs got + new values during unfreezing. If this information is required, + client should call -var-update explicitly. */ } - void mi_cmd_var_show_format (char *command, char **argv, int argc) { @@ -321,12 +316,12 @@ mi_cmd_var_show_format (char *command, char **argv, int argc) if (argc != 1) error (_("-var-show-format: Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); format = varobj_get_display_format (var); - /* Report the current format */ + /* Report the current format. */ ui_out_field_string (uiout, "format", varobj_format_string[(int) format]); } @@ -339,7 +334,7 @@ mi_cmd_var_info_num_children (char *command, char **argv, int argc) if (argc != 1) error (_("-var-info-num-children: Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); ui_out_field_int (uiout, "numchild", varobj_get_num_children (var)); @@ -413,7 +408,7 @@ mi_cmd_var_list_children (char *command, char **argv, int argc) error (_("-var-list-children: Usage: " "[PRINT_VALUES] NAME [FROM TO]")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ if (argc == 1 || argc == 3) var = varobj_get_handle (argv[0]); else @@ -479,7 +474,7 @@ mi_cmd_var_info_type (char *command, char **argv, int argc) if (argc != 1) error (_("-var-info-type: Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); ui_out_field_string (uiout, "type", varobj_get_type (var)); @@ -513,7 +508,7 @@ mi_cmd_var_info_expression (char *command, char **argv, int argc) if (argc != 1) error (_("-var-info-expression: Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); lang = varobj_get_language (var); @@ -554,50 +549,50 @@ mi_cmd_var_evaluate_expression (char *command, char **argv, int argc) enum varobj_display_formats format; int formatFound; - int optind; - char *optarg; + int oind; + char *oarg; enum opt - { - OP_FORMAT - }; - static const struct mi_opt opts[] = { - {"f", OP_FORMAT, 1}, - { 0, 0, 0 } + OP_FORMAT }; + static const struct mi_opt opts[] = + { + {"f", OP_FORMAT, 1}, + { 0, 0, 0 } + }; - /* Parse arguments */ + /* Parse arguments. */ format = FORMAT_NATURAL; formatFound = 0; - optind = 0; + oind = 0; while (1) { int opt = mi_getopt ("-var-evaluate-expression", argc, argv, - opts, &optind, &optarg); + opts, &oind, &oarg); if (opt < 0) break; switch ((enum opt) opt) - { + { case OP_FORMAT: if (formatFound) error (_("Cannot specify format more than once")); - format = mi_parse_format (optarg); + format = mi_parse_format (oarg); formatFound = 1; break; - } + } } - if (optind >= argc) + if (oind >= argc) error (_("Usage: [-f FORMAT] NAME")); - if (optind < argc - 1) + if (oind < argc - 1) error (_("Garbage at end of command")); - /* Get varobj handle, if a valid var obj name was specified */ - var = varobj_get_handle (argv[optind]); + /* Get varobj handle, if a valid var obj name was specified. */ + var = varobj_get_handle (argv[oind]); if (formatFound) { @@ -621,11 +616,12 @@ mi_cmd_var_assign (char *command, char **argv, int argc) struct ui_out *uiout = current_uiout; struct varobj *var; char *expression, *val; + struct cleanup *cleanup; if (argc != 2) error (_("-var-assign: Usage: NAME EXPRESSION.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); if (!varobj_editable_p (var)) @@ -633,6 +629,12 @@ mi_cmd_var_assign (char *command, char **argv, int argc) expression = xstrdup (argv[1]); + /* MI command '-var-assign' may write memory, so suppress memory + changed notification if it does. */ + cleanup + = make_cleanup_restore_integer (&mi_suppress_notification.memory); + mi_suppress_notification.memory = 1; + if (!varobj_set_value (var, expression)) error (_("-var-assign: Could not assign " "expression to variable object")); @@ -640,6 +642,8 @@ mi_cmd_var_assign (char *command, char **argv, int argc) val = varobj_get_value (var); ui_out_field_string (uiout, "value", val); xfree (val); + + do_cleanups (cleanup); } /* Type used for parameters passing to mi_cmd_var_update_iter. */ @@ -672,9 +676,9 @@ mi_cmd_var_update_iter (struct varobj *var, void *data_pointer) thread_stopped = 1; } - if (thread_stopped) - if (!data->only_floating || varobj_floating_p (var)) - varobj_update_one (var, data->print_values, 0 /* implicit */); + if (thread_stopped + && (!data->only_floating || varobj_floating_p (var))) + varobj_update_one (var, data->print_values, 0 /* implicit */); } void @@ -691,7 +695,7 @@ mi_cmd_var_update (char *command, char **argv, int argc) if (argc == 1) name = argv[0]; else - name = (argv[1]); + name = argv[1]; if (argc == 2) print_values = mi_parse_values_option (argv[0]); @@ -703,25 +707,25 @@ mi_cmd_var_update (char *command, char **argv, int argc) else cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changelist"); - /* Check if the parameter is a "*" which means that we want - to update all variables */ + /* Check if the parameter is a "*", which means that we want to + update all variables. */ if ((*name == '*' || *name == '@') && (*(name + 1) == '\0')) { struct mi_cmd_var_update data; - data.only_floating = *name == '@'; + data.only_floating = (*name == '@'); data.print_values = print_values; - /* varobj_update_one automatically updates all the children of VAROBJ. - Therefore update each VAROBJ only once by iterating only the root - VAROBJs. */ + /* varobj_update_one automatically updates all the children of + VAROBJ. Therefore update each VAROBJ only once by iterating + only the root VAROBJs. */ all_root_varobjs (mi_cmd_var_update_iter, &data); } else { - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ struct varobj *var = varobj_get_handle (name); varobj_update_one (var, print_values, 1 /* explicit */); @@ -788,14 +792,14 @@ 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); + display_hint = varobj_get_display_hint (r->varobj); if (display_hint) { ui_out_field_string (uiout, "displayhint", display_hint); xfree (display_hint); } - if (varobj_pretty_printed_p (var)) + if (varobj_pretty_printed_p (r->varobj)) ui_out_field_int (uiout, "dynamic", 1); varobj_get_child_range (r->varobj, &from, &to); @@ -835,6 +839,7 @@ mi_cmd_enable_pretty_printing (char *command, char **argv, int argc) { if (argc != 0) error (_("-enable-pretty-printing: no arguments allowed")); + varobj_enable_pretty_printing (); } diff --git a/contrib/gdb-7/gdb/mi/mi-cmds.c b/contrib/gdb-7/gdb/mi/mi-cmds.c index 81648a7bdc..df173fe493 100644 --- a/contrib/gdb-7/gdb/mi/mi-cmds.c +++ b/contrib/gdb-7/gdb/mi/mi-cmds.c @@ -1,7 +1,5 @@ /* MI Command Set for GDB, the GNU debugger. - - Copyright (C) 2000-2001, 2003, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -24,140 +22,171 @@ #include "top.h" #include "mi-cmds.h" #include "gdb_string.h" +#include "mi-main.h" extern void _initialize_mi_cmds (void); + struct mi_cmd; static struct mi_cmd **lookup_table (const char *command); static void build_table (struct mi_cmd *commands); - -struct mi_cmd mi_cmds[] = +static struct mi_cmd mi_cmds[] = { - { "ada-task-info", { NULL, 0 }, mi_cmd_ada_task_info }, - { "add-inferior", { NULL, 0 }, mi_cmd_add_inferior }, - { "break-after", { "ignore", 1 }, NULL }, - { "break-condition", { "cond", 1 }, NULL }, - { "break-commands", { NULL, 0 }, mi_cmd_break_commands }, - { "break-delete", { "delete breakpoint", 1 }, NULL }, - { "break-disable", { "disable breakpoint", 1 }, NULL }, - { "break-enable", { "enable breakpoint", 1 }, NULL }, - { "break-info", { "info break", 1 }, NULL }, - { "break-insert", { NULL, 0 }, mi_cmd_break_insert}, - { "break-list", { "info break", }, NULL }, - { "break-passcount", { NULL, 0 }, mi_cmd_break_passcount}, - { "break-watch", { NULL, 0 }, mi_cmd_break_watch}, - { "data-disassemble", { NULL, 0 }, mi_cmd_disassemble}, - { "data-evaluate-expression", { NULL, 0 }, mi_cmd_data_evaluate_expression}, - { "data-list-changed-registers", { NULL, 0 }, - mi_cmd_data_list_changed_registers}, - { "data-list-register-names", { NULL, 0 }, mi_cmd_data_list_register_names}, - { "data-list-register-values", { NULL, 0 }, - mi_cmd_data_list_register_values}, - { "data-read-memory", { NULL, 0 }, mi_cmd_data_read_memory}, - { "data-read-memory-bytes", { NULL, 0 }, mi_cmd_data_read_memory_bytes}, - { "data-write-memory", { NULL, 0 }, mi_cmd_data_write_memory}, - { "data-write-memory-bytes", {NULL, 0}, mi_cmd_data_write_memory_bytes}, - { "data-write-register-values", { NULL, 0 }, - mi_cmd_data_write_register_values}, - { "enable-timings", { NULL, 0 }, mi_cmd_enable_timings}, - { "enable-pretty-printing", { NULL, 0 }, mi_cmd_enable_pretty_printing}, - { "environment-cd", { NULL, 0 }, mi_cmd_env_cd}, - { "environment-directory", { NULL, 0 }, mi_cmd_env_dir}, - { "environment-path", { NULL, 0 }, mi_cmd_env_path}, - { "environment-pwd", { NULL, 0 }, mi_cmd_env_pwd}, - { "exec-arguments", { "set args", 1 }, NULL }, - { "exec-continue", { NULL, 0 }, mi_cmd_exec_continue}, - { "exec-finish", { NULL, 0 }, mi_cmd_exec_finish}, - { "exec-jump", { NULL, 0 }, mi_cmd_exec_jump}, - { "exec-interrupt", { NULL, 0 }, mi_cmd_exec_interrupt}, - { "exec-next", { NULL, 0 }, mi_cmd_exec_next}, - { "exec-next-instruction", { NULL, 0 }, mi_cmd_exec_next_instruction}, - { "exec-return", { NULL, 0 }, mi_cmd_exec_return}, - { "exec-run", { NULL, 0}, mi_cmd_exec_run}, - { "exec-step", { NULL, 0 }, mi_cmd_exec_step}, - { "exec-step-instruction", { NULL, 0 }, mi_cmd_exec_step_instruction}, - { "exec-until", { "until", 1 }, NULL}, - { "file-exec-and-symbols", { "file", 1 }, NULL }, - { "file-exec-file", { "exec-file", 1 }, NULL }, - { "file-list-exec-source-file", { NULL, 0 }, - mi_cmd_file_list_exec_source_file}, - { "file-list-exec-source-files", { NULL, 0 }, - mi_cmd_file_list_exec_source_files }, - { "file-symbol-file", { "symbol-file", 1 }, NULL }, - { "gdb-exit", { NULL, 0 }, mi_cmd_gdb_exit}, - { "gdb-set", { "set", 1 }, NULL }, - { "gdb-show", { "show", 1 }, NULL }, - { "gdb-version", { "show version", 0 }, 0 }, - { "inferior-tty-set", { NULL, 0 }, mi_cmd_inferior_tty_set}, - { "inferior-tty-show", { NULL, 0 }, mi_cmd_inferior_tty_show}, - { "interpreter-exec", { NULL, 0 }, mi_cmd_interpreter_exec}, - { "list-features", { NULL, 0 }, mi_cmd_list_features}, - { "list-target-features", { NULL, 0 }, mi_cmd_list_target_features}, - { "list-thread-groups", { NULL, 0 }, mi_cmd_list_thread_groups }, - { "remove-inferior", { NULL, 0 }, mi_cmd_remove_inferior }, - { "stack-info-depth", { NULL, 0 }, mi_cmd_stack_info_depth}, - { "stack-info-frame", { NULL, 0 }, mi_cmd_stack_info_frame}, - { "stack-list-arguments", { NULL, 0 }, mi_cmd_stack_list_args}, - { "stack-list-frames", { NULL, 0 }, mi_cmd_stack_list_frames}, - { "stack-list-locals", { NULL, 0 }, mi_cmd_stack_list_locals}, - { "stack-list-variables", { NULL, 0 }, mi_cmd_stack_list_variables}, - { "stack-select-frame", { NULL, 0 }, mi_cmd_stack_select_frame}, - { "symbol-list-lines", { NULL, 0 }, mi_cmd_symbol_list_lines}, - { "target-attach", { "attach", 1 }, NULL }, - { "target-detach", { NULL, 0 }, mi_cmd_target_detach }, - { "target-disconnect", { "disconnect", 0 }, 0 }, - { "target-download", { "load", 1 }, NULL}, - { "target-file-delete", { NULL, 0 }, mi_cmd_target_file_delete }, - { "target-file-get", { NULL, 0 }, mi_cmd_target_file_get }, - { "target-file-put", { NULL, 0 }, mi_cmd_target_file_put }, - { "target-select", { "target", 1 }, NULL}, - { "thread-info", { NULL, 0 }, mi_cmd_thread_info }, - { "thread-list-ids", { NULL, 0 }, mi_cmd_thread_list_ids}, - { "thread-select", { NULL, 0 }, mi_cmd_thread_select}, - { "trace-define-variable", { NULL, 0 }, mi_cmd_trace_define_variable }, - { "trace-find", { NULL, 0 }, mi_cmd_trace_find }, - { "trace-list-variables", { NULL, 0 }, mi_cmd_trace_list_variables }, - { "trace-save", { NULL, 0 }, mi_cmd_trace_save }, - { "trace-start", { NULL, 0 }, mi_cmd_trace_start }, - { "trace-status", { NULL, 0 }, mi_cmd_trace_status }, - { "trace-stop", { NULL, 0 }, mi_cmd_trace_stop }, - { "var-assign", { NULL, 0 }, mi_cmd_var_assign}, - { "var-create", { NULL, 0 }, mi_cmd_var_create}, - { "var-delete", { NULL, 0 }, mi_cmd_var_delete}, - { "var-evaluate-expression", { NULL, 0 }, mi_cmd_var_evaluate_expression}, - { "var-info-path-expression", { NULL, 0 }, mi_cmd_var_info_path_expression}, - { "var-info-expression", { NULL, 0 }, mi_cmd_var_info_expression}, - { "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-format", { NULL, 0 }, mi_cmd_var_set_format}, - { "var-set-frozen", { NULL, 0 }, mi_cmd_var_set_frozen}, - { "var-set-update-range", { NULL, 0 }, mi_cmd_var_set_update_range }, - { "var-set-visualizer", { NULL, 0 }, mi_cmd_var_set_visualizer}, - { "var-show-attributes", { NULL, 0 }, mi_cmd_var_show_attributes}, - { "var-show-format", { NULL, 0 }, mi_cmd_var_show_format}, - { "var-update", { NULL, 0 }, mi_cmd_var_update}, +/* Define a MI command of NAME, and its corresponding CLI command is + CLI_NAME. */ +#define DEF_MI_CMD_CLI_1(NAME, CLI_NAME, ARGS_P, CALLED) \ + { NAME, { CLI_NAME, ARGS_P}, NULL, CALLED } +#define DEF_MI_CMD_CLI(NAME, CLI_NAME, ARGS_P) \ + DEF_MI_CMD_CLI_1(NAME, CLI_NAME, ARGS_P, NULL) + +/* Define a MI command of NAME, and implemented by function MI_FUNC. */ +#define DEF_MI_CMD_MI_1(NAME, MI_FUNC, CALLED) \ + { NAME, {NULL, 0}, MI_FUNC, CALLED } +#define DEF_MI_CMD_MI(NAME, MI_FUNC) DEF_MI_CMD_MI_1(NAME, MI_FUNC, NULL) + + DEF_MI_CMD_MI ("ada-task-info", mi_cmd_ada_task_info), + DEF_MI_CMD_MI ("add-inferior", mi_cmd_add_inferior), + DEF_MI_CMD_CLI_1 ("break-after", "ignore", 1, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_CLI_1 ("break-condition","cond", 1, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_MI_1 ("break-commands", mi_cmd_break_commands, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_CLI_1 ("break-delete", "delete breakpoint", 1, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_CLI_1 ("break-disable", "disable breakpoint", 1, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_CLI_1 ("break-enable", "enable breakpoint", 1, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_CLI ("break-info", "info break", 1), + DEF_MI_CMD_MI_1 ("break-insert", mi_cmd_break_insert, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_CLI ("break-list", "info break", 0), + DEF_MI_CMD_MI_1 ("break-passcount", mi_cmd_break_passcount, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_MI_1 ("break-watch", mi_cmd_break_watch, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_MI_1 ("catch-load", mi_cmd_catch_load, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_MI_1 ("catch-unload", mi_cmd_catch_unload, + &mi_suppress_notification.breakpoint), + DEF_MI_CMD_MI ("data-disassemble", mi_cmd_disassemble), + DEF_MI_CMD_MI ("data-evaluate-expression", mi_cmd_data_evaluate_expression), + DEF_MI_CMD_MI ("data-list-changed-registers", + mi_cmd_data_list_changed_registers), + DEF_MI_CMD_MI ("data-list-register-names", mi_cmd_data_list_register_names), + DEF_MI_CMD_MI ("data-list-register-values", mi_cmd_data_list_register_values), + DEF_MI_CMD_MI ("data-read-memory", mi_cmd_data_read_memory), + DEF_MI_CMD_MI ("data-read-memory-bytes", mi_cmd_data_read_memory_bytes), + DEF_MI_CMD_MI_1 ("data-write-memory", mi_cmd_data_write_memory, + &mi_suppress_notification.memory), + DEF_MI_CMD_MI_1 ("data-write-memory-bytes", mi_cmd_data_write_memory_bytes, + &mi_suppress_notification.memory), + DEF_MI_CMD_MI ("data-write-register-values", + mi_cmd_data_write_register_values), + DEF_MI_CMD_MI ("enable-timings", mi_cmd_enable_timings), + DEF_MI_CMD_MI ("enable-pretty-printing", mi_cmd_enable_pretty_printing), + DEF_MI_CMD_MI ("environment-cd", mi_cmd_env_cd), + DEF_MI_CMD_MI ("environment-directory", mi_cmd_env_dir), + DEF_MI_CMD_MI ("environment-path", mi_cmd_env_path), + DEF_MI_CMD_MI ("environment-pwd", mi_cmd_env_pwd), + DEF_MI_CMD_CLI ("exec-arguments", "set args", 1), + DEF_MI_CMD_MI ("exec-continue", mi_cmd_exec_continue), + DEF_MI_CMD_MI ("exec-finish", mi_cmd_exec_finish), + DEF_MI_CMD_MI ("exec-jump", mi_cmd_exec_jump), + DEF_MI_CMD_MI ("exec-interrupt", mi_cmd_exec_interrupt), + DEF_MI_CMD_MI ("exec-next", mi_cmd_exec_next), + DEF_MI_CMD_MI ("exec-next-instruction", mi_cmd_exec_next_instruction), + DEF_MI_CMD_MI ("exec-return", mi_cmd_exec_return), + DEF_MI_CMD_MI ("exec-run", mi_cmd_exec_run), + DEF_MI_CMD_MI ("exec-step", mi_cmd_exec_step), + DEF_MI_CMD_MI ("exec-step-instruction", mi_cmd_exec_step_instruction), + DEF_MI_CMD_CLI ("exec-until", "until", 1), + DEF_MI_CMD_CLI ("file-exec-and-symbols", "file", 1), + DEF_MI_CMD_CLI ("file-exec-file", "exec-file", 1), + DEF_MI_CMD_MI ("file-list-exec-source-file", + mi_cmd_file_list_exec_source_file), + DEF_MI_CMD_MI ("file-list-exec-source-files", + mi_cmd_file_list_exec_source_files), + DEF_MI_CMD_CLI ("file-symbol-file", "symbol-file", 1), + DEF_MI_CMD_MI ("gdb-exit", mi_cmd_gdb_exit), + DEF_MI_CMD_CLI_1 ("gdb-set", "set", 1, + &mi_suppress_notification.cmd_param_changed), + DEF_MI_CMD_CLI ("gdb-show", "show", 1), + DEF_MI_CMD_CLI ("gdb-version", "show version", 0), + DEF_MI_CMD_MI ("inferior-tty-set", mi_cmd_inferior_tty_set), + DEF_MI_CMD_MI ("inferior-tty-show", mi_cmd_inferior_tty_show), + DEF_MI_CMD_MI ("info-os", mi_cmd_info_os), + DEF_MI_CMD_MI ("interpreter-exec", mi_cmd_interpreter_exec), + DEF_MI_CMD_MI ("list-features", mi_cmd_list_features), + DEF_MI_CMD_MI ("list-target-features", mi_cmd_list_target_features), + DEF_MI_CMD_MI ("list-thread-groups", mi_cmd_list_thread_groups), + DEF_MI_CMD_MI ("remove-inferior", mi_cmd_remove_inferior), + DEF_MI_CMD_MI ("stack-info-depth", mi_cmd_stack_info_depth), + DEF_MI_CMD_MI ("stack-info-frame", mi_cmd_stack_info_frame), + DEF_MI_CMD_MI ("stack-list-arguments", mi_cmd_stack_list_args), + DEF_MI_CMD_MI ("stack-list-frames", mi_cmd_stack_list_frames), + DEF_MI_CMD_MI ("stack-list-locals", mi_cmd_stack_list_locals), + DEF_MI_CMD_MI ("stack-list-variables", mi_cmd_stack_list_variables), + DEF_MI_CMD_MI ("stack-select-frame", mi_cmd_stack_select_frame), + DEF_MI_CMD_MI ("symbol-list-lines", mi_cmd_symbol_list_lines), + DEF_MI_CMD_CLI ("target-attach", "attach", 1), + DEF_MI_CMD_MI ("target-detach", mi_cmd_target_detach), + DEF_MI_CMD_CLI ("target-disconnect", "disconnect", 0), + DEF_MI_CMD_CLI ("target-download", "load", 1), + DEF_MI_CMD_MI ("target-file-delete", mi_cmd_target_file_delete), + DEF_MI_CMD_MI ("target-file-get", mi_cmd_target_file_get), + DEF_MI_CMD_MI ("target-file-put", mi_cmd_target_file_put), + DEF_MI_CMD_CLI ("target-select", "target", 1), + DEF_MI_CMD_MI ("thread-info", mi_cmd_thread_info), + DEF_MI_CMD_MI ("thread-list-ids", mi_cmd_thread_list_ids), + DEF_MI_CMD_MI ("thread-select", mi_cmd_thread_select), + DEF_MI_CMD_MI ("trace-define-variable", mi_cmd_trace_define_variable), + DEF_MI_CMD_MI_1 ("trace-find", mi_cmd_trace_find, + &mi_suppress_notification.traceframe), + DEF_MI_CMD_MI ("trace-list-variables", mi_cmd_trace_list_variables), + DEF_MI_CMD_MI ("trace-save", mi_cmd_trace_save), + DEF_MI_CMD_MI ("trace-start", mi_cmd_trace_start), + DEF_MI_CMD_MI ("trace-status", mi_cmd_trace_status), + DEF_MI_CMD_MI ("trace-stop", mi_cmd_trace_stop), + DEF_MI_CMD_MI ("var-assign", mi_cmd_var_assign), + DEF_MI_CMD_MI ("var-create", mi_cmd_var_create), + DEF_MI_CMD_MI ("var-delete", mi_cmd_var_delete), + DEF_MI_CMD_MI ("var-evaluate-expression", mi_cmd_var_evaluate_expression), + DEF_MI_CMD_MI ("var-info-path-expression", mi_cmd_var_info_path_expression), + DEF_MI_CMD_MI ("var-info-expression", mi_cmd_var_info_expression), + DEF_MI_CMD_MI ("var-info-num-children", mi_cmd_var_info_num_children), + DEF_MI_CMD_MI ("var-info-type", mi_cmd_var_info_type), + DEF_MI_CMD_MI ("var-list-children", mi_cmd_var_list_children), + DEF_MI_CMD_MI ("var-set-format", mi_cmd_var_set_format), + DEF_MI_CMD_MI ("var-set-frozen", mi_cmd_var_set_frozen), + DEF_MI_CMD_MI ("var-set-update-range", mi_cmd_var_set_update_range), + DEF_MI_CMD_MI ("var-set-visualizer", mi_cmd_var_set_visualizer), + DEF_MI_CMD_MI ("var-show-attributes", mi_cmd_var_show_attributes), + DEF_MI_CMD_MI ("var-show-format", mi_cmd_var_show_format), + DEF_MI_CMD_MI ("var-update", mi_cmd_var_update), { NULL, } }; -/* Pointer to the mi command table (built at run time) */ +/* Pointer to the mi command table (built at run time). */ static struct mi_cmd **mi_table; -/* A prime large enough to accomodate the entire command table */ +/* A prime large enough to accomodate the entire command table. */ enum { MI_TABLE_SIZE = 227 }; -/* Exported function used to obtain info from the table */ +/* Exported function used to obtain info from the table. */ struct mi_cmd * mi_lookup (const char *command) { return *lookup_table (command); } -/* stat collecting */ +/* Used for collecting hash hit/miss statistics. */ + struct mi_cmd_stats { int hit; @@ -166,20 +195,21 @@ struct mi_cmd_stats }; struct mi_cmd_stats stats; -/* our lookup function */ +/* Look up a command. */ + static struct mi_cmd ** lookup_table (const char *command) { const char *chp; unsigned int index = 0; - /* compute our hash */ + /* Compute our hash. */ for (chp = command; *chp; chp++) { - /* some what arbitrary */ + /* We use a somewhat arbitrary formula. */ index = ((index << 6) + (unsigned int) *chp) % MI_TABLE_SIZE; } - /* look it up */ + while (1) { struct mi_cmd **entry = &mi_table[index]; @@ -218,6 +248,7 @@ build_table (struct mi_cmd *commands) _("command `%s' appears to be duplicated"), command->name); *entry = command; + /* FIXME lose these prints */ if (0) { fprintf_unfiltered (gdb_stdlog, "%-30s %2d\n", diff --git a/contrib/gdb-7/gdb/mi/mi-cmds.h b/contrib/gdb-7/gdb/mi/mi-cmds.h index 309a3cede7..fdf6f9ca54 100644 --- a/contrib/gdb-7/gdb/mi/mi-cmds.h +++ b/contrib/gdb-7/gdb/mi/mi-cmds.h @@ -1,7 +1,6 @@ /* MI Command Set for GDB, the GNU debugger. - Copyright (C) 2000, 2003-2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -35,13 +34,16 @@ extern const char mi_all_values[]; typedef void (mi_cmd_argv_ftype) (char *command, char **argv, int argc); -/* Function implementing each command */ +/* Declarations of the functions implementing each command. */ + extern mi_cmd_argv_ftype mi_cmd_ada_task_info; extern mi_cmd_argv_ftype mi_cmd_add_inferior; extern mi_cmd_argv_ftype mi_cmd_break_insert; extern mi_cmd_argv_ftype mi_cmd_break_commands; extern mi_cmd_argv_ftype mi_cmd_break_passcount; extern mi_cmd_argv_ftype mi_cmd_break_watch; +extern mi_cmd_argv_ftype mi_cmd_catch_load; +extern mi_cmd_argv_ftype mi_cmd_catch_unload; extern mi_cmd_argv_ftype mi_cmd_disassemble; extern mi_cmd_argv_ftype mi_cmd_data_evaluate_expression; extern mi_cmd_argv_ftype mi_cmd_data_list_register_names; @@ -72,6 +74,7 @@ extern mi_cmd_argv_ftype mi_cmd_file_list_exec_source_files; extern mi_cmd_argv_ftype mi_cmd_gdb_exit; extern mi_cmd_argv_ftype mi_cmd_inferior_tty_set; extern mi_cmd_argv_ftype mi_cmd_inferior_tty_show; +extern mi_cmd_argv_ftype mi_cmd_info_os; extern mi_cmd_argv_ftype mi_cmd_interpreter_exec; extern mi_cmd_argv_ftype mi_cmd_list_features; extern mi_cmd_argv_ftype mi_cmd_list_target_features; @@ -117,7 +120,7 @@ extern mi_cmd_argv_ftype mi_cmd_var_update; extern mi_cmd_argv_ftype mi_cmd_enable_pretty_printing; extern mi_cmd_argv_ftype mi_cmd_var_set_update_range; -/* Description of a single command. */ +/* Description of a single command. */ struct mi_cli { @@ -129,16 +132,22 @@ struct mi_cli struct mi_cmd { - /* official name of the command. */ + /* Official name of the command. */ const char *name; /* The corresponding CLI command that can be used to implement this MI command (if cli.lhs is non NULL). */ struct mi_cli cli; /* If non-null, the function implementing the MI command. */ mi_cmd_argv_ftype *argv_func; + /* If non-null, the pointer to a field in + 'struct mi_suppress_notification', which will be set to true by MI + command processor (mi-main.c:mi_cmd_execute) when this command is + being executed. It will be set back to false when command has been + executed. */ + int *suppress_notification; }; -/* Lookup a command in the mi comand table */ +/* Lookup a command in the MI command table. */ extern struct mi_cmd *mi_lookup (const char *command); @@ -148,6 +157,6 @@ extern int mi_debug_p; /* Raw console output - FIXME: should this be a parameter? */ extern struct ui_file *raw_stdout; -extern void mi_execute_command (char *cmd, int from_tty); +extern void mi_execute_command (const char *cmd, int from_tty); #endif diff --git a/contrib/gdb-7/gdb/mi/mi-common.c b/contrib/gdb-7/gdb/mi/mi-common.c index 1eaa99011b..4fce613fde 100644 --- a/contrib/gdb-7/gdb/mi/mi-common.c +++ b/contrib/gdb-7/gdb/mi/mi-common.c @@ -1,5 +1,5 @@ /* Interface for common GDB/MI data - Copyright (C) 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -43,7 +43,8 @@ static const char * const async_reason_string_lookup[] = NULL }; -static_assert (ARRAY_SIZE (async_reason_string_lookup) == EXEC_ASYNC_LAST + 1); +gdb_static_assert (ARRAY_SIZE (async_reason_string_lookup) + == EXEC_ASYNC_LAST + 1); const char * async_reason_lookup (enum async_reply_reason reason) diff --git a/contrib/gdb-7/gdb/mi/mi-common.h b/contrib/gdb-7/gdb/mi/mi-common.h index d7f459cb5f..3590897ea0 100644 --- a/contrib/gdb-7/gdb/mi/mi-common.h +++ b/contrib/gdb-7/gdb/mi/mi-common.h @@ -1,5 +1,5 @@ /* Interface for common GDB/MI data - Copyright (C) 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/mi/mi-console.c b/contrib/gdb-7/gdb/mi/mi-console.c index 6b4601b224..2c34ced52a 100644 --- a/contrib/gdb-7/gdb/mi/mi-console.c +++ b/contrib/gdb-7/gdb/mi/mi-console.c @@ -1,6 +1,6 @@ /* MI Console code. - Copyright (C) 2000-2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -19,12 +19,15 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +/* An MI console is a kind of ui_file stream that sends output to + stdout, but encapsulated and prefixed with a distinctive string; + for instance, error output is normally identified by a leading + "&". */ + #include "defs.h" #include "mi-console.h" #include "gdb_string.h" -/* MI-console: send output to std-out but correcty encapsulated */ - static ui_file_fputs_ftype mi_console_file_fputs; static ui_file_flush_ftype mi_console_file_flush; static ui_file_delete_ftype mi_console_file_delete; @@ -38,11 +41,15 @@ struct mi_console_file char quote; }; -int mi_console_file_magic; +/* Use the address of this otherwise-unused global as a magic number + identifying this class of ui_file objects. */ +static int mi_console_file_magic; + +/* Create a console that wraps the given output stream RAW with the + string PREFIX and quoting it with QUOTE. */ struct ui_file * -mi_console_file_new (struct ui_file *raw, - const char *prefix, char quote) +mi_console_file_new (struct ui_file *raw, const char *prefix, char quote) { struct ui_file *ui_file = ui_file_new (); struct mi_console_file *mi_console = XMALLOC (struct mi_console_file); @@ -55,6 +62,7 @@ mi_console_file_new (struct ui_file *raw, set_ui_file_fputs (ui_file, mi_console_file_fputs); set_ui_file_flush (ui_file, mi_console_file_flush); set_ui_file_data (ui_file, mi_console, mi_console_file_delete); + return ui_file; } @@ -66,36 +74,36 @@ mi_console_file_delete (struct ui_file *file) if (mi_console->magic != &mi_console_file_magic) internal_error (__FILE__, __LINE__, _("mi_console_file_delete: bad magic number")); + xfree (mi_console); } static void -mi_console_file_fputs (const char *buf, - struct ui_file *file) +mi_console_file_fputs (const char *buf, struct ui_file *file) { struct mi_console_file *mi_console = ui_file_data (file); if (mi_console->magic != &mi_console_file_magic) internal_error (__FILE__, __LINE__, "mi_console_file_fputs: bad magic number"); - /* Append the text to our internal buffer */ + + /* Append the text to our internal buffer. */ fputs_unfiltered (buf, mi_console->buffer); - /* Flush when an embedded \n */ + /* Flush when an embedded newline is present anywhere in the buffer. */ if (strchr (buf, '\n') != NULL) gdb_flush (file); } -/* Transform a byte sequence into a console output packet. */ +/* Transform a byte sequence into a console output packet. */ + static void -mi_console_raw_packet (void *data, - const char *buf, - long length_buf) +mi_console_raw_packet (void *data, const char *buf, long length_buf) { struct mi_console_file *mi_console = data; if (mi_console->magic != &mi_console_file_magic) internal_error (__FILE__, __LINE__, - _("mi_console_file_transform: bad magic number")); + _("mi_console_raw_packet: bad magic number")); if (length_buf > 0) { @@ -124,6 +132,24 @@ mi_console_file_flush (struct ui_file *file) if (mi_console->magic != &mi_console_file_magic) internal_error (__FILE__, __LINE__, _("mi_console_file_flush: bad magic number")); + ui_file_put (mi_console->buffer, mi_console_raw_packet, mi_console); ui_file_rewind (mi_console->buffer); + +} + +/* Change the underlying stream of the console directly; this is + useful as a minimum-impact way to reflect external changes like + logging enable/disable. */ + +void +mi_console_set_raw (struct ui_file *file, struct ui_file *raw) +{ + struct mi_console_file *mi_console = ui_file_data (file); + + if (mi_console->magic != &mi_console_file_magic) + internal_error (__FILE__, __LINE__, + _("mi_console_file_set_raw: bad magic number")); + + mi_console->raw = raw; } diff --git a/contrib/gdb-7/gdb/mi/mi-console.h b/contrib/gdb-7/gdb/mi/mi-console.h index 9727eb6c79..7d9410b07a 100644 --- a/contrib/gdb-7/gdb/mi/mi-console.h +++ b/contrib/gdb-7/gdb/mi/mi-console.h @@ -1,5 +1,5 @@ /* MI Command Set - MI Console. - Copyright (C) 2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. @@ -24,4 +24,7 @@ extern struct ui_file *mi_console_file_new (struct ui_file *raw, const char *prefix, char quote); +extern void mi_console_set_raw (struct ui_file *console, + struct ui_file *raw); + #endif diff --git a/contrib/gdb-7/gdb/mi/mi-getopt.c b/contrib/gdb-7/gdb/mi/mi-getopt.c index 2e288a29c0..a1e2ccc587 100644 --- a/contrib/gdb-7/gdb/mi/mi-getopt.c +++ b/contrib/gdb-7/gdb/mi/mi-getopt.c @@ -1,5 +1,5 @@ /* MI Command Set - MI Option Parser. - Copyright (C) 2000-2001, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. @@ -25,49 +25,49 @@ int mi_getopt (const char *prefix, int argc, char **argv, const struct mi_opt *opts, - int *optind, char **optarg) + int *oind, char **oarg) { char *arg; const struct mi_opt *opt; - /* We assume that argv/argc are ok. */ - if (*optind > argc || *optind < 0) + /* We assume that argv/argc are ok. */ + if (*oind > argc || *oind < 0) internal_error (__FILE__, __LINE__, - _("mi_getopt_long: optind out of bounds")); - if (*optind == argc) + _("mi_getopt_long: oind out of bounds")); + if (*oind == argc) return -1; - arg = argv[*optind]; + arg = argv[*oind]; /* ``--''? */ if (strcmp (arg, "--") == 0) { - *optind += 1; - *optarg = NULL; + *oind += 1; + *oarg = NULL; return -1; } - /* End of option list. */ + /* End of option list. */ if (arg[0] != '-') { - *optarg = NULL; + *oarg = NULL; return -1; } - /* Look the option up. */ + /* Look the option up. */ for (opt = opts; opt->name != NULL; opt++) { if (strcmp (opt->name, arg + 1) != 0) continue; if (opt->arg_p) { - /* A non-simple optarg option. */ - if (argc < *optind + 2) + /* A non-simple oarg option. */ + if (argc < *oind + 2) error (_("%s: Option %s requires an argument"), prefix, arg); - *optarg = argv[(*optind) + 1]; - *optind = (*optind) + 2; + *oarg = argv[(*oind) + 1]; + *oind = (*oind) + 2; return opt->index; } else { - *optarg = NULL; - *optind = (*optind) + 1; + *oarg = NULL; + *oind = (*oind) + 1; return opt->index; } } @@ -77,14 +77,14 @@ mi_getopt (const char *prefix, int mi_valid_noargs (const char *prefix, int argc, char **argv) { - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; static const struct mi_opt opts[] = - { - { 0, 0, 0 } - }; + { + { 0, 0, 0 } + }; - if (mi_getopt (prefix, argc, argv, opts, &optind, &optarg) == -1) + if (mi_getopt (prefix, argc, argv, opts, &oind, &oarg) == -1) return 1; else return 0; diff --git a/contrib/gdb-7/gdb/mi/mi-getopt.h b/contrib/gdb-7/gdb/mi/mi-getopt.h index ea09b44070..960035318e 100644 --- a/contrib/gdb-7/gdb/mi/mi-getopt.h +++ b/contrib/gdb-7/gdb/mi/mi-getopt.h @@ -1,5 +1,5 @@ /* MI Option Parser. - Copyright (C) 2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. @@ -20,6 +20,16 @@ #ifndef MI_GETOPT_H #define MI_GETOPT_H +/* The option list. Terminated by NAME==NULL. ARG_P that the option + requires an argument. INDEX is returned to identify the option. */ + +struct mi_opt + { + const char *name; + int index; + int arg_p; + }; + /* Like getopt() but with simpler semantics. An option has the form ``-''. The special option ``--'' @@ -37,30 +47,16 @@ to specify the non-option argument. OPTARG is set to NULL. mi_getopt() calls ``error("%s: Unknown option %c", prefix, - option)'' if an unknown option is encountered. */ + option)'' if an unknown option is encountered. */ -struct mi_opt; extern int mi_getopt (const char *prefix, int argc, char **argv, const struct mi_opt *opt, int *optind, char **optarg); -/* The option list. Terminated by NAME==NULL. ARG_P that the option - requires an argument. INDEX is returned to identify th option. */ - -struct mi_opt - { - const char *name; - int index; - int arg_p; - }; - -struct mi_opt; - -/* mi_valid_noargs - - Determines if ARGC/ARGV are a valid set of parameters to satisfy - an MI function that is not supposed to recieve any arguments. +/* mi_valid_noargs determines if ARGC/ARGV are a valid set of + parameters to satisfy an MI function that is not supposed to + recieve any arguments. - An MI function that should not recieve arguments can still be + An MI function that should not receive arguments can still be passed parameters after the special option '--' such as below. Example: The MI function -exec-run takes no args. diff --git a/contrib/gdb-7/gdb/mi/mi-interp.c b/contrib/gdb-7/gdb/mi/mi-interp.c index c9cd24d676..2702f4f093 100644 --- a/contrib/gdb-7/gdb/mi/mi-interp.c +++ b/contrib/gdb-7/gdb/mi/mi-interp.c @@ -1,6 +1,6 @@ /* MI Interpreter Definitions and Commands for GDB, the GNU debugger. - Copyright (C) 2002-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -35,16 +35,22 @@ #include "gdbthread.h" #include "solist.h" #include "gdb.h" +#include "objfiles.h" +#include "tracepoint.h" -/* These are the interpreter setup, etc. functions for the MI interpreter */ -static void mi_execute_command_wrapper (char *cmd); +/* These are the interpreter setup, etc. functions for the MI + interpreter. */ + +static void mi_execute_command_wrapper (const char *cmd); +static void mi_execute_command_input_handler (char *cmd); static void mi_command_loop (int mi_version); /* These are hooks that we put in place while doing interpreter_exec - so we can report interesting things that happened "behind the mi's - back" in this command */ + so we can report interesting things that happened "behind the MI's + back" in this command. */ + static int mi_interp_query_hook (const char *ctlstr, va_list ap) - ATTRIBUTE_PRINTF (1, 0); + ATTRIBUTE_PRINTF (1, 0); static void mi3_command_loop (void); static void mi2_command_loop (void); @@ -56,6 +62,7 @@ static void mi_on_normal_stop (struct bpstats *bs, int print_frame); static void mi_new_thread (struct thread_info *t); static void mi_thread_exit (struct thread_info *t, int silent); +static void mi_record_changed (struct inferior*, int); static void mi_inferior_added (struct inferior *inf); static void mi_inferior_appeared (struct inferior *inf); static void mi_inferior_exit (struct inferior *inf); @@ -64,9 +71,16 @@ static void mi_on_resume (ptid_t ptid); static void mi_solib_loaded (struct so_list *solib); static void mi_solib_unloaded (struct so_list *solib); static void mi_about_to_proceed (void); +static void mi_traceframe_changed (int tfnum, int tpnum); +static void mi_tsv_created (const struct trace_state_variable *tsv); +static void mi_tsv_deleted (const struct trace_state_variable *tsv); +static void mi_tsv_modified (const struct trace_state_variable *tsv); static void mi_breakpoint_created (struct breakpoint *b); static void mi_breakpoint_deleted (struct breakpoint *b); static void mi_breakpoint_modified (struct breakpoint *b); +static void mi_command_param_changed (const char *param, const char *value); +static void mi_memory_changed (struct inferior *inf, CORE_ADDR memaddr, + ssize_t len, const bfd_byte *myaddr); static int report_initial_inferior (struct inferior *inf, void *closure); @@ -77,14 +91,15 @@ mi_interpreter_init (struct interp *interp, int top_level) const char *name; int mi_version; - /* HACK: We need to force stdout/stderr to point at the console. This avoids - any potential side effects caused by legacy code that is still - using the TUI / fputs_unfiltered_hook. So we set up output channels for - this now, and swap them in when we are run. */ + /* Assign the output channel created at startup to its own global, + so that we can create a console channel that encapsulates and + prefixes all gdb_output-type bits coming from the rest of the + debugger. */ - raw_stdout = stdio_fileopen (stdout); + raw_stdout = gdb_stdout; - /* Create MI channels */ + /* Create MI console channels, each with a different prefix so they + can be distinguished. */ mi->out = mi_console_file_new (raw_stdout, "~", '"'); mi->err = mi_console_file_new (raw_stdout, "&", '"'); mi->log = mi->err; @@ -115,18 +130,26 @@ mi_interpreter_init (struct interp *interp, int top_level) observer_attach_inferior_appeared (mi_inferior_appeared); observer_attach_inferior_exit (mi_inferior_exit); observer_attach_inferior_removed (mi_inferior_removed); + observer_attach_record_changed (mi_record_changed); observer_attach_normal_stop (mi_on_normal_stop); observer_attach_target_resumed (mi_on_resume); observer_attach_solib_loaded (mi_solib_loaded); observer_attach_solib_unloaded (mi_solib_unloaded); observer_attach_about_to_proceed (mi_about_to_proceed); + observer_attach_traceframe_changed (mi_traceframe_changed); + observer_attach_tsv_created (mi_tsv_created); + observer_attach_tsv_deleted (mi_tsv_deleted); + observer_attach_tsv_modified (mi_tsv_modified); observer_attach_breakpoint_created (mi_breakpoint_created); observer_attach_breakpoint_deleted (mi_breakpoint_deleted); observer_attach_breakpoint_modified (mi_breakpoint_modified); + observer_attach_command_param_changed (mi_command_param_changed); + observer_attach_memory_changed (mi_memory_changed); - /* The initial inferior is created before this function is called, so we - need to report it explicitly. Use iteration in case future version - of GDB creates more than one inferior up-front. */ + /* The initial inferior is created before this function is + called, so we need to report it explicitly. Use iteration in + case future version of GDB creates more than one inferior + up-front. */ iterate_over_inferiors (report_initial_inferior, mi); } @@ -138,13 +161,14 @@ mi_interpreter_resume (void *data) { struct mi_interp *mi = data; - /* As per hack note in mi_interpreter_init, swap in the output channels... */ + /* As per hack note in mi_interpreter_init, swap in the output + channels... */ gdb_setup_readline (); /* These overwrite some of the initialization done in _intialize_event_loop. */ call_readline = gdb_readline2; - input_handler = mi_execute_command_wrapper; + input_handler = mi_execute_command_input_handler; add_file_handler (input_fd, stdin_event_handler, 0); async_command_editing_p = 0; /* FIXME: This is a total hack for now. PB's use of the MI @@ -156,12 +180,12 @@ mi_interpreter_resume (void *data) sync_execution = 0; gdb_stdout = mi->out; - /* Route error and log output through the MI */ + /* Route error and log output through the MI. */ gdb_stderr = mi->err; gdb_stdlog = mi->log; - /* Route target output through the MI. */ + /* Route target output through the MI. */ gdb_stdtarg = mi->targ; - /* Route target error through the MI as well. */ + /* Route target error through the MI as well. */ gdb_stdtargerr = mi->targ; /* Replace all the hooks that we know about. There really needs to @@ -170,7 +194,7 @@ mi_interpreter_resume (void *data) deprecated_show_load_progress = mi_load_progress; - /* If we're _the_ interpreter, take control. */ + /* If we're _the_ interpreter, take control. */ if (current_interp_named_p (INTERP_MI1)) deprecated_command_loop_hook = mi1_command_loop; else if (current_interp_named_p (INTERP_MI2)) @@ -193,14 +217,12 @@ mi_interpreter_suspend (void *data) static struct gdb_exception mi_interpreter_exec (void *data, const char *command) { - char *tmp = alloca (strlen (command) + 1); - - strcpy (tmp, command); - mi_execute_command_wrapper (tmp); + mi_execute_command_wrapper (command); return exception_none; } -/* Never display the default gdb prompt in mi case. */ +/* Never display the default GDB prompt in MI case. */ + static int mi_interpreter_prompt_p (void *data) { @@ -229,13 +251,14 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc) "does not support command execution"), argv[0]); - /* Insert the MI out hooks, making sure to also call the interpreter's hooks - if it has any. */ - /* KRS: We shouldn't need this... Events should be installed and they should - just ALWAYS fire something out down the MI channel... */ + /* Insert the MI out hooks, making sure to also call the + interpreter's hooks if it has any. */ + /* KRS: We shouldn't need this... Events should be installed and + they should just ALWAYS fire something out down the MI + channel. */ mi_insert_notify_hooks (); - /* Now run the code... */ + /* Now run the code. */ old_chain = make_cleanup (null_cleanup, 0); for (i = 1; i < argc; i++) @@ -257,14 +280,12 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc) do_cleanups (old_chain); } -/* - * mi_insert_notify_hooks - This inserts a number of hooks that are - * meant to produce async-notify ("=") MI messages while running - * commands in another interpreter using mi_interpreter_exec. The - * canonical use for this is to allow access to the gdb CLI - * interpreter from within the MI, while still producing MI style - * output when actions in the CLI command change gdb's state. -*/ +/* This inserts a number of hooks that are meant to produce + async-notify ("=") MI messages while running commands in another + interpreter using mi_interpreter_exec. The canonical use for this + is to allow access to the gdb CLI interpreter from within the MI, + while still producing MI style output when actions in the CLI + command change GDB's state. */ static void mi_insert_notify_hooks (void) @@ -285,11 +306,22 @@ mi_interp_query_hook (const char *ctlstr, va_list ap) } static void -mi_execute_command_wrapper (char *cmd) +mi_execute_command_wrapper (const char *cmd) { mi_execute_command (cmd, stdin == instream); } +/* mi_execute_command_wrapper wrapper suitable for INPUT_HANDLER. */ + +static void +mi_execute_command_input_handler (char *cmd) +{ + mi_execute_command_wrapper (cmd); + + fputs_unfiltered ("(gdb) \n", raw_stdout); + gdb_flush (raw_stdout); +} + static void mi1_command_loop (void) { @@ -312,11 +344,13 @@ static void mi_command_loop (int mi_version) { /* Turn off 8 bit strings in quoted output. Any character with the - high bit set is printed using C's octal format. */ + high bit set is printed using C's octal format. */ sevenbit_strings = 1; - /* Tell the world that we're alive */ + + /* Tell the world that we're alive. */ fputs_unfiltered ("(gdb) \n", raw_stdout); gdb_flush (raw_stdout); + start_event_loop (); } @@ -353,6 +387,19 @@ mi_thread_exit (struct thread_info *t, int silent) gdb_flush (mi->event_channel); } +/* Emit notification on changing the state of record. */ + +static void +mi_record_changed (struct inferior *inferior, int started) +{ + struct mi_interp *mi = top_level_interpreter_data (); + + fprintf_unfiltered (mi->event_channel, "record-%s,thread-group=\"i%d\"", + started ? "started" : "stopped", inferior->num); + + gdb_flush (mi->event_channel); +} + static void mi_inferior_added (struct inferior *inf) { @@ -420,11 +467,11 @@ mi_on_normal_stop (struct bpstats *bs, int print_frame) if (current_uiout != mi_uiout) { - /* The normal_stop function has printed frame information into - CLI uiout, or some other non-MI uiout. There's no way we - can extract proper fields from random uiout object, so we print - the frame again. In practice, this can only happen when running - a CLI command in MI. */ + /* The normal_stop function has printed frame information + into CLI uiout, or some other non-MI uiout. There's no + way we can extract proper fields from random uiout + object, so we print the frame again. In practice, this + can only happen when running a CLI command in MI. */ struct ui_out *saved_uiout = current_uiout; struct target_waitstatus last; ptid_t last_ptid; @@ -481,19 +528,108 @@ mi_about_to_proceed (void) mi_proceeded = 1; } -/* When non-zero, no MI notifications will be emitted in - response to breakpoint change observers. */ -int mi_suppress_breakpoint_notifications = 0; +/* When the element is non-zero, no MI notifications will be emitted in + response to the corresponding observers. */ + +struct mi_suppress_notification mi_suppress_notification = + { + 0, + 0, + 0, + }; + +/* Emit notification on changing a traceframe. */ + +static void +mi_traceframe_changed (int tfnum, int tpnum) +{ + struct mi_interp *mi = top_level_interpreter_data (); + + if (mi_suppress_notification.traceframe) + return; + + target_terminal_ours (); + + if (tfnum >= 0) + fprintf_unfiltered (mi->event_channel, "traceframe-changed," + "num=\"%d\",tracepoint=\"%d\"\n", + tfnum, tpnum); + else + fprintf_unfiltered (mi->event_channel, "traceframe-changed,end"); + + gdb_flush (mi->event_channel); +} + +/* Emit notification on creating a trace state variable. */ + +static void +mi_tsv_created (const struct trace_state_variable *tsv) +{ + struct mi_interp *mi = top_level_interpreter_data (); + + target_terminal_ours (); + + fprintf_unfiltered (mi->event_channel, "tsv-created," + "name=\"%s\",initial=\"%s\"\n", + tsv->name, plongest (tsv->initial_value)); + + gdb_flush (mi->event_channel); +} + +/* Emit notification on deleting a trace state variable. */ + +static void +mi_tsv_deleted (const struct trace_state_variable *tsv) +{ + struct mi_interp *mi = top_level_interpreter_data (); + + target_terminal_ours (); + + if (tsv != NULL) + fprintf_unfiltered (mi->event_channel, "tsv-deleted," + "name=\"%s\"\n", tsv->name); + else + fprintf_unfiltered (mi->event_channel, "tsv-deleted\n"); + + gdb_flush (mi->event_channel); +} + +/* Emit notification on modifying a trace state variable. */ + +static void +mi_tsv_modified (const struct trace_state_variable *tsv) +{ + struct mi_interp *mi = top_level_interpreter_data (); + struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); + + target_terminal_ours (); + + fprintf_unfiltered (mi->event_channel, + "tsv-modified"); + + ui_out_redirect (mi_uiout, mi->event_channel); + + ui_out_field_string (mi_uiout, "name", tsv->name); + ui_out_field_string (mi_uiout, "initial", + plongest (tsv->initial_value)); + if (tsv->value_known) + ui_out_field_string (mi_uiout, "current", plongest (tsv->value)); + + ui_out_redirect (mi_uiout, NULL); + + gdb_flush (mi->event_channel); +} /* Emit notification about a created breakpoint. */ + static void mi_breakpoint_created (struct breakpoint *b) { struct mi_interp *mi = top_level_interpreter_data (); struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); - struct gdb_exception e; + volatile struct gdb_exception e; - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -503,12 +639,12 @@ mi_breakpoint_created (struct breakpoint *b) fprintf_unfiltered (mi->event_channel, "breakpoint-created"); /* We want the output from gdb_breakpoint_query to go to - mi->event_channel. One approach would be to just - call gdb_breakpoint_query, and then use mi_out_put to - send the current content of mi_outout into mi->event_channel. - However, that will break if anything is output to mi_uiout - prior the calling the breakpoint_created notifications. - So, we use ui_out_redirect. */ + mi->event_channel. One approach would be to just call + gdb_breakpoint_query, and then use mi_out_put to send the current + content of mi_outout into mi->event_channel. However, that will + break if anything is output to mi_uiout prior to calling the + breakpoint_created notifications. So, we use + ui_out_redirect. */ ui_out_redirect (mi_uiout, mi->event_channel); TRY_CATCH (e, RETURN_MASK_ERROR) gdb_breakpoint_query (mi_uiout, b->number, NULL); @@ -518,12 +654,13 @@ mi_breakpoint_created (struct breakpoint *b) } /* Emit notification about deleted breakpoint. */ + static void mi_breakpoint_deleted (struct breakpoint *b) { struct mi_interp *mi = top_level_interpreter_data (); - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -538,14 +675,15 @@ mi_breakpoint_deleted (struct breakpoint *b) } /* Emit notification about modified breakpoint. */ + static void mi_breakpoint_modified (struct breakpoint *b) { struct mi_interp *mi = top_level_interpreter_data (); struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); - struct gdb_exception e; + volatile struct gdb_exception e; - if (mi_suppress_breakpoint_notifications) + if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) @@ -555,12 +693,12 @@ mi_breakpoint_modified (struct breakpoint *b) fprintf_unfiltered (mi->event_channel, "breakpoint-modified"); /* We want the output from gdb_breakpoint_query to go to - mi->event_channel. One approach would be to just - call gdb_breakpoint_query, and then use mi_out_put to - send the current content of mi_outout into mi->event_channel. - However, that will break if anything is output to mi_uiout - prior the calling the breakpoint_created notifications. - So, we use ui_out_redirect. */ + mi->event_channel. One approach would be to just call + gdb_breakpoint_query, and then use mi_out_put to send the current + content of mi_outout into mi->event_channel. However, that will + break if anything is output to mi_uiout prior to calling the + breakpoint_created notifications. So, we use + ui_out_redirect. */ ui_out_redirect (mi_uiout, mi->event_channel); TRY_CATCH (e, RETURN_MASK_ERROR) gdb_breakpoint_query (mi_uiout, b->number, NULL); @@ -569,7 +707,6 @@ mi_breakpoint_modified (struct breakpoint *b) gdb_flush (mi->event_channel); } - static int mi_output_running_pid (struct thread_info *info, void *arg) { @@ -667,7 +804,7 @@ mi_solib_loaded (struct so_list *solib) struct mi_interp *mi = top_level_interpreter_data (); target_terminal_ours (); - if (gdbarch_has_global_solist (target_gdbarch)) + if (gdbarch_has_global_solist (target_gdbarch ())) fprintf_unfiltered (mi->event_channel, "library-loaded,id=\"%s\",target-name=\"%s\"," "host-name=\"%s\",symbols-loaded=\"%d\"", @@ -691,7 +828,7 @@ mi_solib_unloaded (struct so_list *solib) struct mi_interp *mi = top_level_interpreter_data (); target_terminal_ours (); - if (gdbarch_has_global_solist (target_gdbarch)) + if (gdbarch_has_global_solist (target_gdbarch ())) fprintf_unfiltered (mi->event_channel, "library-unloaded,id=\"%s\",target-name=\"%s\"," "host-name=\"%s\"", @@ -707,6 +844,73 @@ mi_solib_unloaded (struct so_list *solib) gdb_flush (mi->event_channel); } +/* Emit notification about the command parameter change. */ + +static void +mi_command_param_changed (const char *param, const char *value) +{ + struct mi_interp *mi = top_level_interpreter_data (); + struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); + + if (mi_suppress_notification.cmd_param_changed) + return; + + target_terminal_ours (); + + fprintf_unfiltered (mi->event_channel, + "cmd-param-changed"); + + ui_out_redirect (mi_uiout, mi->event_channel); + + ui_out_field_string (mi_uiout, "param", param); + ui_out_field_string (mi_uiout, "value", value); + + ui_out_redirect (mi_uiout, NULL); + + gdb_flush (mi->event_channel); +} + +/* Emit notification about the target memory change. */ + +static void +mi_memory_changed (struct inferior *inferior, CORE_ADDR memaddr, + ssize_t len, const bfd_byte *myaddr) +{ + struct mi_interp *mi = top_level_interpreter_data (); + struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); + struct obj_section *sec; + + if (mi_suppress_notification.memory) + return; + + target_terminal_ours (); + + fprintf_unfiltered (mi->event_channel, + "memory-changed"); + + ui_out_redirect (mi_uiout, mi->event_channel); + + ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num); + ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr); + ui_out_field_fmt (mi_uiout, "len", "0x%zx", len); + + /* Append 'type=code' into notification if MEMADDR falls in the range of + sections contain code. */ + sec = find_pc_section (memaddr); + if (sec != NULL && sec->objfile != NULL) + { + flagword flags = bfd_get_section_flags (sec->objfile->obfd, + sec->the_bfd_section); + + if (flags & SEC_CODE) + ui_out_field_string (mi_uiout, "type", "code"); + } + + ui_out_redirect (mi_uiout, NULL); + + gdb_flush (mi->event_channel); +} + static int report_initial_inferior (struct inferior *inf, void *closure) { @@ -732,20 +936,69 @@ mi_ui_out (struct interp *interp) return mi->uiout; } +/* Save the original value of raw_stdout here when logging, so we can + restore correctly when done. */ + +static struct ui_file *saved_raw_stdout; + +/* Do MI-specific logging actions; save raw_stdout, and change all + the consoles to use the supplied ui-file(s). */ + +static int +mi_set_logging (struct interp *interp, int start_log, + struct ui_file *out, struct ui_file *logfile) +{ + struct mi_interp *mi = interp_data (interp); + + if (!mi) + return 0; + + if (start_log) + { + /* The tee created already is based on gdb_stdout, which for MI + is a console and so we end up in an infinite loop of console + writing to ui_file writing to console etc. So discard the + existing tee (it hasn't been used yet, and MI won't ever use + it), and create one based on raw_stdout instead. */ + if (logfile) + { + ui_file_delete (out); + out = tee_file_new (raw_stdout, 0, logfile, 0); + } + + saved_raw_stdout = raw_stdout; + raw_stdout = out; + } + else + { + raw_stdout = saved_raw_stdout; + saved_raw_stdout = NULL; + } + + mi_console_set_raw (mi->out, raw_stdout); + mi_console_set_raw (mi->err, raw_stdout); + mi_console_set_raw (mi->log, raw_stdout); + mi_console_set_raw (mi->targ, raw_stdout); + mi_console_set_raw (mi->event_channel, raw_stdout); + + return 1; +} + extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */ void _initialize_mi_interp (void) { static const struct interp_procs procs = - { - mi_interpreter_init, /* init_proc */ - mi_interpreter_resume, /* resume_proc */ - mi_interpreter_suspend, /* suspend_proc */ - mi_interpreter_exec, /* exec_proc */ - mi_interpreter_prompt_p, /* prompt_proc_p */ - mi_ui_out /* ui_out_proc */ - }; + { + mi_interpreter_init, /* init_proc */ + mi_interpreter_resume, /* resume_proc */ + mi_interpreter_suspend, /* suspend_proc */ + mi_interpreter_exec, /* exec_proc */ + mi_interpreter_prompt_p, /* prompt_proc_p */ + mi_ui_out, /* ui_out_proc */ + mi_set_logging /* set_logging_proc */ + }; /* The various interpreter levels. */ interp_add (interp_new (INTERP_MI1, &procs)); diff --git a/contrib/gdb-7/gdb/mi/mi-main.c b/contrib/gdb-7/gdb/mi/mi-main.c index b170f01ab4..57821aa0e3 100644 --- a/contrib/gdb-7/gdb/mi/mi-main.c +++ b/contrib/gdb-7/gdb/mi/mi-main.c @@ -1,6 +1,6 @@ /* MI Command Set. - Copyright (C) 2000-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -19,8 +19,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* Work in progress. */ - #include "defs.h" #include "arch-utils.h" #include "target.h" @@ -71,18 +69,19 @@ enum }; int mi_debug_p; + struct ui_file *raw_stdout; -/* This is used to pass the current command timestamp - down to continuation routines. */ +/* This is used to pass the current command timestamp down to + continuation routines. */ static struct mi_timestamp *current_command_ts; static int do_timings = 0; char *current_token; -/* Few commands would like to know if options like --thread-group - were explicitly specified. This variable keeps the current - parsed command including all option, and make it possible. */ +/* Few commands would like to know if options like --thread-group were + explicitly specified. This variable keeps the current parsed + command including all option, and make it possible. */ static struct mi_parse *current_context; int running_result_record_printed = 1; @@ -178,7 +177,7 @@ void mi_cmd_exec_return (char *command, char **argv, int argc) { /* This command doesn't really execute the target, it just pops the - specified number of frames. */ + specified number of frames. */ if (argc) /* Call return_command with from_tty argument equal to 0 so as to avoid being queried. */ @@ -211,10 +210,9 @@ proceed_thread (struct thread_info *thread, int pid) switch_to_thread (thread->ptid); clear_proceed_status (); - proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0); } - static int proceed_thread_callback (struct thread_info *thread, void *arg) { @@ -229,9 +227,10 @@ exec_continue (char **argv, int argc) { if (non_stop) { - /* In non-stop mode, 'resume' always resumes a single thread. Therefore, - to resume all threads of the current inferior, or all threads in all - inferiors, we need to iterate over threads. + /* In non-stop mode, 'resume' always resumes a single thread. + Therefore, to resume all threads of the current inferior, or + all threads in all inferiors, we need to iterate over + threads. See comment on infcmd.c:proceed_thread_callback for rationale. */ if (current_context->all || current_context->thread_group != -1) @@ -265,9 +264,10 @@ exec_continue (char **argv, int argc) } else { - /* In all-stop mode, -exec-continue traditionally resumed either - all threads, or one thread, depending on the 'scheduler-locking' - variable. Let's continue to do the same. */ + /* In all-stop mode, -exec-continue traditionally resumed + either all threads, or one thread, depending on the + 'scheduler-locking' variable. Let's continue to do the + same. */ continue_1 (1); } do_cleanups (back_to); @@ -322,11 +322,12 @@ interrupt_thread_callback (struct thread_info *thread, void *arg) return 0; } -/* Interrupt the execution of the target. Note how we must play around - with the token variables, in order to display the current token in - the result of the interrupt command, and the previous execution - token when the target finally stops. See comments in +/* Interrupt the execution of the target. Note how we must play + around with the token variables, in order to display the current + token in the result of the interrupt command, and the previous + execution token when the target finally stops. See comments in mi_cmd_execute. */ + void mi_cmd_exec_interrupt (char *command, char **argv, int argc) { @@ -507,6 +508,8 @@ mi_cmd_thread_info (char *command, char **argv, int argc) print_thread_info (current_uiout, argv[0], -1); } +DEF_VEC_I(int); + struct collect_cores_data { int pid; @@ -567,10 +570,10 @@ print_one_inferior (struct inferior *inferior, void *xdata) if (inferior->pid != 0) ui_out_field_int (uiout, "pid", inferior->pid); - if (inferior->pspace->ebfd) + if (inferior->pspace->pspace_exec_filename != NULL) { ui_out_field_string (uiout, "executable", - bfd_get_filename (inferior->pspace->ebfd)); + inferior->pspace->pspace_exec_filename); } data.cores = 0; @@ -609,8 +612,9 @@ print_one_inferior (struct inferior *inferior, void *xdata) return 0; } -/* Output a field named 'cores' with a list as the value. The elements of - the list are obtained by splitting 'cores' on comma. */ +/* Output a field named 'cores' with a list as the value. The + elements of the list are obtained by splitting 'cores' on + comma. */ static void output_cores (struct ui_out *uiout, const char *field_name, const char *xcores) @@ -797,23 +801,23 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc) VEC (int) *ids = 0; enum opt - { - AVAILABLE_OPT, RECURSE_OPT - }; - static const struct mi_opt opts[] = { - {"-available", AVAILABLE_OPT, 0}, - {"-recurse", RECURSE_OPT, 1}, - { 0, 0, 0 } + AVAILABLE_OPT, RECURSE_OPT }; + static const struct mi_opt opts[] = + { + {"-available", AVAILABLE_OPT, 0}, + {"-recurse", RECURSE_OPT, 1}, + { 0, 0, 0 } + }; - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; while (1) { int opt = mi_getopt ("-list-thread-groups", argc, argv, opts, - &optind, &optarg); + &oind, &oarg); if (opt < 0) break; @@ -823,9 +827,9 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc) available = 1; break; case RECURSE_OPT: - if (strcmp (optarg, "0") == 0) + if (strcmp (oarg, "0") == 0) ; - else if (strcmp (optarg, "1") == 0) + else if (strcmp (oarg, "1") == 0) recurse = 1; else error (_("only '0' and '1' are valid values " @@ -834,18 +838,18 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc) } } - for (; optind < argc; ++optind) + for (; oind < argc; ++oind) { char *end; int inf; - if (*(argv[optind]) != 'i') - error (_("invalid syntax of group id '%s'"), argv[optind]); + if (*(argv[oind]) != 'i') + error (_("invalid syntax of group id '%s'"), argv[oind]); - inf = strtoul (argv[optind] + 1, &end, 0); + inf = strtoul (argv[oind] + 1, &end, 0); if (*end != '\0') - error (_("invalid syntax of group id '%s'"), argv[optind]); + error (_("invalid syntax of group id '%s'"), argv[oind]); VEC_safe_push (int, ids, inf); } if (VEC_length (int, ids) > 1) @@ -861,7 +865,7 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc) } else if (VEC_length (int, ids) == 1) { - /* Local thread groups, single id. */ + /* Local thread groups, single id. */ int id = *VEC_address (int, ids); struct inferior *inf = find_inferior_id (id); @@ -899,10 +903,11 @@ mi_cmd_data_list_register_names (char *command, char **argv, int argc) struct cleanup *cleanup; /* Note that the test for a valid register must include checking the - gdbarch_register_name because gdbarch_num_regs may be allocated for - the union of the register sets within a family of related processors. - In this case, some entries of gdbarch_register_name will change depending - upon the particular processor being debugged. */ + gdbarch_register_name because gdbarch_num_regs may be allocated + for the union of the register sets within a family of related + processors. In this case, some entries of gdbarch_register_name + will change depending upon the particular processor being + debugged. */ gdbarch = get_current_arch (); numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); @@ -952,27 +957,30 @@ mi_cmd_data_list_changed_registers (char *command, char **argv, int argc) int i; struct cleanup *cleanup; - /* The last time we visited this function, the current frame's register - contents were saved in THIS_REGS. Move THIS_REGS over to PREV_REGS, - and refresh THIS_REGS with the now-current register contents. */ + /* The last time we visited this function, the current frame's + register contents were saved in THIS_REGS. Move THIS_REGS over + to PREV_REGS, and refresh THIS_REGS with the now-current register + contents. */ prev_regs = this_regs; this_regs = frame_save_as_regcache (get_selected_frame (NULL)); cleanup = make_cleanup_regcache_xfree (prev_regs); /* Note that the test for a valid register must include checking the - gdbarch_register_name because gdbarch_num_regs may be allocated for - the union of the register sets within a family of related processors. - In this case, some entries of gdbarch_register_name will change depending - upon the particular processor being debugged. */ + gdbarch_register_name because gdbarch_num_regs may be allocated + for the union of the register sets within a family of related + processors. In this case, some entries of gdbarch_register_name + will change depending upon the particular processor being + debugged. */ gdbarch = get_regcache_arch (this_regs); numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); make_cleanup_ui_out_list_begin_end (uiout, "changed-registers"); - if (argc == 0) /* No args, just do all the regs. */ + if (argc == 0) { + /* No args, just do all the regs. */ for (regnum = 0; regnum < numregs; regnum++) @@ -1042,11 +1050,13 @@ register_changed_p (int regnum, struct regcache *prev_regs, /* Return a list of register number and value pairs. The valid arguments expected are: a letter indicating the format in which to - display the registers contents. This can be one of: x (hexadecimal), d - (decimal), N (natural), t (binary), o (octal), r (raw). After the - format argumetn there can be a sequence of numbers, indicating which - registers to fetch the content of. If the format is the only argument, - a list of all the registers with their values is returned. */ + display the registers contents. This can be one of: x + (hexadecimal), d (decimal), N (natural), t (binary), o (octal), r + (raw). After the format argument there can be a sequence of + numbers, indicating which registers to fetch the content of. If + the format is the only argument, a list of all the registers with + their values is returned. */ + void mi_cmd_data_list_register_values (char *command, char **argv, int argc) { @@ -1058,10 +1068,11 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) struct cleanup *list_cleanup, *tuple_cleanup; /* Note that the test for a valid register must include checking the - gdbarch_register_name because gdbarch_num_regs may be allocated for - the union of the register sets within a family of related processors. - In this case, some entries of gdbarch_register_name will change depending - upon the particular processor being debugged. */ + gdbarch_register_name because gdbarch_num_regs may be allocated + for the union of the register sets within a family of related + processors. In this case, some entries of gdbarch_register_name + will change depending upon the particular processor being + debugged. */ if (argc == 0) error (_("-data-list-register-values: Usage: " @@ -1075,8 +1086,9 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "register-values"); - if (argc == 1) /* No args, beside the format: do all the regs. */ + if (argc == 1) { + /* No args, beside the format: do all the regs. */ for (regnum = 0; regnum < numregs; regnum++) @@ -1113,18 +1125,14 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) } /* Output one register's contents in the desired format. */ + static void get_register (struct frame_info *frame, int regnum, int format) { struct gdbarch *gdbarch = get_frame_arch (frame); struct ui_out *uiout = current_uiout; - CORE_ADDR addr; - enum lval_type lval; - struct ui_stream *stb; struct value *val; - stb = ui_out_stream_new (uiout); - if (format == 'N') format = 0; @@ -1150,20 +1158,24 @@ get_register (struct frame_info *frame, int regnum, int format) ptr += 2; } ui_out_field_string (uiout, "value", buf); - /*fputs_filtered (buf, gdb_stdout); */ } else { struct value_print_options opts; + struct ui_file *stb; + struct cleanup *old_chain; + + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); get_formatted_print_options (&opts, format); opts.deref_ref = 1; val_print (value_type (val), value_contents_for_printing (val), value_embedded_offset (val), 0, - stb->stream, 0, val, &opts, current_language); + stb, 0, val, &opts, current_language); ui_out_field_stream (uiout, "value", stb); - ui_out_stream_delete (stb); + do_cleanups (old_chain); } } @@ -1177,13 +1189,13 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc) struct regcache *regcache; struct gdbarch *gdbarch; int numregs, i; - char format; /* Note that the test for a valid register must include checking the - gdbarch_register_name because gdbarch_num_regs may be allocated for - the union of the register sets within a family of related processors. - In this case, some entries of gdbarch_register_name will change depending - upon the particular processor being debugged. */ + gdbarch_register_name because gdbarch_num_regs may be allocated + for the union of the register sets within a family of related + processors. In this case, some entries of gdbarch_register_name + will change depending upon the particular processor being + debugged. */ regcache = get_current_regcache (); gdbarch = get_regcache_arch (regcache); @@ -1193,8 +1205,6 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc) error (_("-data-write-register-values: Usage: -data-write-register-" "values [ ... ]")); - format = (int) argv[0][0]; - if (!target_has_registers) error (_("-data-write-register-values: No registers.")); @@ -1229,43 +1239,41 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc) /* Evaluate the value of the argument. The argument is an expression. If the expression contains spaces it needs to be included in double quotes. */ + void mi_cmd_data_evaluate_expression (char *command, char **argv, int argc) { struct expression *expr; - struct cleanup *old_chain = NULL; + struct cleanup *old_chain; struct value *val; - struct ui_stream *stb = NULL; + struct ui_file *stb; struct value_print_options opts; struct ui_out *uiout = current_uiout; - stb = ui_out_stream_new (uiout); + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); if (argc != 1) - { - ui_out_stream_delete (stb); - error (_("-data-evaluate-expression: " - "Usage: -data-evaluate-expression expression")); - } + error (_("-data-evaluate-expression: " + "Usage: -data-evaluate-expression expression")); expr = parse_expression (argv[0]); - old_chain = make_cleanup (free_current_contents, &expr); + make_cleanup (free_current_contents, &expr); val = evaluate_expression (expr); /* Print the result of the expression evaluation. */ get_user_print_options (&opts); opts.deref_ref = 0; - common_val_print (val, stb->stream, 0, &opts, current_language); + common_val_print (val, stb, 0, &opts, current_language); ui_out_field_stream (uiout, "value", stb); - ui_out_stream_delete (stb); do_cleanups (old_chain); } -/* DATA-MEMORY-READ: +/* This is the -data-read-memory command. ADDR: start address of data to be dumped. WORD-FORMAT: a char indicating format for the ``word''. See @@ -1282,7 +1290,7 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc) {addr="...",rowN={wordN="..." ,... [,ascii="..."]}, ...} Returns: - The number of bytes read is SIZE*ROW*COL. */ + The number of bytes read is SIZE*ROW*COL. */ void mi_cmd_data_read_memory (char *command, char **argv, int argc) @@ -1291,9 +1299,7 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) struct ui_out *uiout = current_uiout; struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); CORE_ADDR addr; - long total_bytes; - long nr_cols; - long nr_rows; + long total_bytes, nr_cols, nr_rows; char word_format; struct type *word_type; long word_size; @@ -1302,34 +1308,34 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) gdb_byte *mbuf; int nr_bytes; long offset = 0; - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; enum opt - { - OFFSET_OPT - }; - static const struct mi_opt opts[] = { - {"o", OFFSET_OPT, 1}, - { 0, 0, 0 } + OFFSET_OPT }; + static const struct mi_opt opts[] = + { + {"o", OFFSET_OPT, 1}, + { 0, 0, 0 } + }; while (1) { int opt = mi_getopt ("-data-read-memory", argc, argv, opts, - &optind, &optarg); + &oind, &oarg); if (opt < 0) break; switch ((enum opt) opt) { case OFFSET_OPT: - offset = atol (optarg); + offset = atol (oarg); break; } } - argv += optind; - argc -= optind; + argv += oind; + argc -= oind; if (argc < 5 || argc > 6) error (_("-data-read-memory: Usage: " @@ -1340,7 +1346,7 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) /* Start address of the memory dump. */ addr = parse_and_eval_address (argv[0]) + offset; /* The format character to use when displaying a memory word. See - the ``x'' command. */ + the ``x'' command. */ word_format = argv[1][0]; /* The size of the memory word. */ word_size = atol (argv[2]); @@ -1408,12 +1414,15 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) /* Build the result as a two dimentional table. */ { - struct ui_stream *stream = ui_out_stream_new (uiout); - struct cleanup *cleanup_list_memory; + struct ui_file *stream; + struct cleanup *cleanup_stream; int row; int row_byte; - cleanup_list_memory = make_cleanup_ui_out_list_begin_end (uiout, "memory"); + stream = mem_fileopen (); + cleanup_stream = make_cleanup_ui_file_delete (stream); + + make_cleanup_ui_out_list_begin_end (uiout, "memory"); for (row = 0, row_byte = 0; row < nr_rows; row++, row_byte += nr_cols * word_size) @@ -1440,9 +1449,9 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) } else { - ui_file_rewind (stream->stream); + ui_file_rewind (stream); print_scalar_formatted (mbuf + col_byte, word_type, &opts, - word_asize, stream->stream); + word_asize, stream); ui_out_field_stream (uiout, NULL, stream); } } @@ -1451,27 +1460,22 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) { int byte; - ui_file_rewind (stream->stream); + ui_file_rewind (stream); for (byte = row_byte; byte < row_byte + word_size * nr_cols; byte++) { if (byte >= nr_bytes) - { - fputc_unfiltered ('X', stream->stream); - } + fputc_unfiltered ('X', stream); else if (mbuf[byte] < 32 || mbuf[byte] > 126) - { - fputc_unfiltered (aschar, stream->stream); - } + fputc_unfiltered (aschar, stream); else - fputc_unfiltered (mbuf[byte], stream->stream); + fputc_unfiltered (mbuf[byte], stream); } ui_out_field_stream (uiout, "ascii", stream); } do_cleanups (cleanup_tuple); } - ui_out_stream_delete (stream); - do_cleanups (cleanup_list_memory); + do_cleanups (cleanup_stream); } do_cleanups (cleanups); } @@ -1488,33 +1492,33 @@ mi_cmd_data_read_memory_bytes (char *command, char **argv, int argc) int ix; VEC(memory_read_result_s) *result; long offset = 0; - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; enum opt - { - OFFSET_OPT - }; - static const struct mi_opt opts[] = { - {"o", OFFSET_OPT, 1}, - { 0, 0, 0 } + OFFSET_OPT }; + static const struct mi_opt opts[] = + { + {"o", OFFSET_OPT, 1}, + { 0, 0, 0 } + }; while (1) { int opt = mi_getopt ("-data-read-memory-bytes", argc, argv, opts, - &optind, &optarg); + &oind, &oarg); if (opt < 0) break; switch ((enum opt) opt) { case OFFSET_OPT: - offset = atol (optarg); + offset = atol (oarg); break; } } - argv += optind; - argc -= optind; + argv += oind; + argc -= oind; if (argc != 2) error (_("Usage: [ -o OFFSET ] ADDR LENGTH.")); @@ -1558,8 +1562,7 @@ mi_cmd_data_read_memory_bytes (char *command, char **argv, int argc) do_cleanups (cleanups); } - -/* DATA-MEMORY-WRITE: +/* Implementation of the -data-write_memory command. COLUMN_OFFSET: optional argument. Must be preceded by '-o'. The offset from the beginning of the memory grid row where the cell to @@ -1575,13 +1578,13 @@ mi_cmd_data_read_memory_bytes (char *command, char **argv, int argc) Writes VALUE into ADDR + (COLUMN_OFFSET * WORD_SIZE). Prints nothing. */ + void mi_cmd_data_write_memory (char *command, char **argv, int argc) { struct gdbarch *gdbarch = get_current_arch (); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR addr; - char word_format; long word_size; /* FIXME: ezannoni 2000-02-17 LONGEST could possibly not be big enough when using a compiler other than GCC. */ @@ -1589,34 +1592,34 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc) void *buffer; struct cleanup *old_chain; long offset = 0; - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; enum opt - { - OFFSET_OPT - }; - static const struct mi_opt opts[] = { - {"o", OFFSET_OPT, 1}, - { 0, 0, 0 } + OFFSET_OPT }; + static const struct mi_opt opts[] = + { + {"o", OFFSET_OPT, 1}, + { 0, 0, 0 } + }; while (1) { int opt = mi_getopt ("-data-write-memory", argc, argv, opts, - &optind, &optarg); + &oind, &oarg); if (opt < 0) break; switch ((enum opt) opt) { case OFFSET_OPT: - offset = atol (optarg); + offset = atol (oarg); break; } } - argv += optind; - argc -= optind; + argv += oind; + argc -= oind; if (argc != 4) error (_("-data-write-memory: Usage: " @@ -1625,10 +1628,7 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc) /* Extract all the arguments. */ /* Start address of the memory dump. */ addr = parse_and_eval_address (argv[0]); - /* The format character to use when displaying a memory word. See - the ``x'' command. */ - word_format = argv[1][0]; - /* The size of the memory word. */ + /* The size of the memory word. */ word_size = atol (argv[2]); /* Calculate the real address of the write destination. */ @@ -1641,49 +1641,81 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc) old_chain = make_cleanup (xfree, buffer); store_signed_integer (buffer, word_size, byte_order, value); /* Write it down to memory. */ - write_memory (addr, buffer, word_size); + write_memory_with_notification (addr, buffer, word_size); /* Free the buffer. */ do_cleanups (old_chain); } -/* DATA-MEMORY-WRITE-RAW: +/* Implementation of the -data-write-memory-bytes command. ADDR: start address - DATA: string of bytes to write at that address. */ + DATA: string of bytes to write at that address + COUNT: number of bytes to be filled (decimal integer). */ + void mi_cmd_data_write_memory_bytes (char *command, char **argv, int argc) { CORE_ADDR addr; char *cdata; gdb_byte *data; - int len, r, i; + gdb_byte *databuf; + size_t len, i, steps, remainder; + long int count, j; struct cleanup *back_to; - if (argc != 2) - error (_("Usage: ADDR DATA.")); + if (argc != 2 && argc != 3) + error (_("Usage: ADDR DATA [COUNT].")); addr = parse_and_eval_address (argv[0]); cdata = argv[1]; + if (strlen (cdata) % 2) + error (_("Hex-encoded '%s' must have an even number of characters."), + cdata); + len = strlen (cdata)/2; + if (argc == 3) + count = strtoul (argv[2], NULL, 10); + else + count = len; - data = xmalloc (len); - back_to = make_cleanup (xfree, data); + databuf = xmalloc (len * sizeof (gdb_byte)); + back_to = make_cleanup (xfree, databuf); for (i = 0; i < len; ++i) { int x; - sscanf (cdata + i * 2, "%02x", &x); - data[i] = (gdb_byte)x; + if (sscanf (cdata + i * 2, "%02x", &x) != 1) + error (_("Invalid argument")); + databuf[i] = (gdb_byte) x; + } + + if (len < count) + { + /* Pattern is made of less bytes than count: + repeat pattern to fill memory. */ + data = xmalloc (count); + make_cleanup (xfree, data); + + steps = count / len; + remainder = count % len; + for (j = 0; j < steps; j++) + memcpy (data + j * len, databuf, len); + + if (remainder > 0) + memcpy (data + steps * len, databuf, remainder); + } + else + { + /* Pattern is longer than or equal to count: + just copy len bytes. */ + data = databuf; } - r = target_write_memory (addr, data, len); - if (r != 0) - error (_("Could not write memory")); + write_memory_with_notification (addr, data, count); do_cleanups (back_to); } - void mi_cmd_enable_timings (char *command, char **argv, int argc) { @@ -1768,8 +1800,8 @@ mi_cmd_add_inferior (char *command, char **argv, int argc) ui_out_field_fmt (current_uiout, "inferior", "i%d", inf->num); } -/* Callback used to find the first inferior other than the - current one. */ +/* Callback used to find the first inferior other than the current + one. */ static int get_other_inferior (struct inferior *inf, void *arg) @@ -1825,7 +1857,7 @@ mi_cmd_remove_inferior (char *command, char **argv, int argc) args->action will tell mi_execute_command what action to perfrom after the given command has executed (display/suppress - prompt, display error). */ + prompt, display error). */ static void captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context) @@ -1849,15 +1881,14 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context) fprintf_unfiltered (raw_stdout, " token=`%s' command=`%s' args=`%s'\n", context->token, context->command, context->args); - mi_cmd_execute (context); /* Print the result if there were no errors. Remember that on the way out of executing a command, you have - to directly use the mi_interp's uiout, since the command could - have reset the interpreter, in which case the current uiout - will most likely crash in the mi_out_* routines. */ + to directly use the mi_interp's uiout, since the command + could have reset the interpreter, in which case the current + uiout will most likely crash in the mi_out_* routines. */ if (!running_result_record_printed) { fputs_unfiltered (context->token, raw_stdout); @@ -1871,9 +1902,9 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context) fputs_unfiltered ("\n", raw_stdout); } else - /* The command does not want anything to be printed. In that - case, the command probably should not have written anything - to uiout, but in case it has written something, discard it. */ + /* The command does not want anything to be printed. In that + case, the command probably should not have written anything + to uiout, but in case it has written something, discard it. */ mi_out_rewind (uiout); break; @@ -1911,12 +1942,9 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context) } break; } - } do_cleanups (cleanup); - - return; } /* Print a gdb exception to the MI output stream. */ @@ -1934,7 +1962,7 @@ mi_print_exception (const char *token, struct gdb_exception exception) } void -mi_execute_command (char *cmd, int from_tty) +mi_execute_command (const char *cmd, int from_tty) { char *token; struct mi_parse *command = NULL; @@ -2025,11 +2053,6 @@ mi_execute_command (char *cmd, int from_tty) mi_parse_free (command); } - - fputs_unfiltered ("(gdb) \n", raw_stdout); - gdb_flush (raw_stdout); - /* Print any buffered hook code. */ - /* ..... */ } static void @@ -2061,9 +2084,10 @@ mi_cmd_execute (struct mi_parse *parse) set_current_inferior (inf); /* This behaviour means that if --thread-group option identifies - an inferior with multiple threads, then a random one will be picked. - This is not a problem -- frontend should always provide --thread if - it wishes to operate on a specific thread. */ + an inferior with multiple threads, then a random one will be + picked. This is not a problem -- frontend should always + provide --thread if it wishes to operate on a specific + thread. */ if (inf->pid != 0) tp = any_live_thread_of_process (inf->pid); switch_to_thread (tp ? tp->ptid : null_ptid); @@ -2098,10 +2122,10 @@ mi_cmd_execute (struct mi_parse *parse) current_context = parse; - if (strncmp (parse->command, "break-", sizeof ("break-") - 1 ) == 0) + if (parse->cmd->suppress_notification != NULL) { - make_cleanup_restore_integer (&mi_suppress_breakpoint_notifications); - mi_suppress_breakpoint_notifications = 1; + make_cleanup_restore_integer (parse->cmd->suppress_notification); + *parse->cmd->suppress_notification = 1; } if (parse->cmd->argv_func != NULL) @@ -2154,7 +2178,7 @@ mi_execute_cli_command (const char *cmd, int args_p, const char *args) fprintf_unfiltered (gdb_stdout, "cli=%s run=%s\n", cmd, run); old_cleanups = make_cleanup (xfree, run); - execute_command ( /*ui */ run, 0 /*from_tty */ ); + execute_command (run, 0 /* from_tty */ ); do_cleanups (old_cleanups); return; } @@ -2172,7 +2196,7 @@ mi_execute_async_cli_command (char *cli_command, char **argv, int argc) run = xstrprintf ("%s %s", cli_command, argc ? *argv : ""); old_cleanups = make_cleanup (xfree, run); - execute_command ( /*ui */ run, 0 /*from_tty */ ); + execute_command (run, 0 /* from_tty */ ); /* Do this before doing any printing. It would appear that some print code leaves garbage around in the buffer. */ @@ -2273,67 +2297,66 @@ mi_load_progress (const char *section_name, static void timestamp (struct mi_timestamp *tv) - { - gettimeofday (&tv->wallclock, NULL); +{ + gettimeofday (&tv->wallclock, NULL); #ifdef HAVE_GETRUSAGE - getrusage (RUSAGE_SELF, &rusage); - tv->utime.tv_sec = rusage.ru_utime.tv_sec; - tv->utime.tv_usec = rusage.ru_utime.tv_usec; - tv->stime.tv_sec = rusage.ru_stime.tv_sec; - tv->stime.tv_usec = rusage.ru_stime.tv_usec; + getrusage (RUSAGE_SELF, &rusage); + tv->utime.tv_sec = rusage.ru_utime.tv_sec; + tv->utime.tv_usec = rusage.ru_utime.tv_usec; + tv->stime.tv_sec = rusage.ru_stime.tv_sec; + tv->stime.tv_usec = rusage.ru_stime.tv_usec; #else - { - long usec = get_run_time (); + { + long usec = get_run_time (); - tv->utime.tv_sec = usec/1000000L; - tv->utime.tv_usec = usec - 1000000L*tv->utime.tv_sec; - tv->stime.tv_sec = 0; - tv->stime.tv_usec = 0; - } -#endif + tv->utime.tv_sec = usec/1000000L; + tv->utime.tv_usec = usec - 1000000L*tv->utime.tv_sec; + tv->stime.tv_sec = 0; + tv->stime.tv_usec = 0; } +#endif +} static void print_diff_now (struct mi_timestamp *start) - { - struct mi_timestamp now; +{ + struct mi_timestamp now; - timestamp (&now); - print_diff (start, &now); - } + timestamp (&now); + print_diff (start, &now); +} void mi_print_timing_maybe (void) { - /* If the command is -enable-timing then do_timings may be - true whilst current_command_ts is not initialized. */ + /* If the command is -enable-timing then do_timings may be true + whilst current_command_ts is not initialized. */ if (do_timings && current_command_ts) print_diff_now (current_command_ts); } static long timeval_diff (struct timeval start, struct timeval end) - { - return ((end.tv_sec - start.tv_sec) * 1000000L) - + (end.tv_usec - start.tv_usec); - } +{ + return ((end.tv_sec - start.tv_sec) * 1000000L) + + (end.tv_usec - start.tv_usec); +} static void print_diff (struct mi_timestamp *start, struct mi_timestamp *end) - { - fprintf_unfiltered - (raw_stdout, - ",time={wallclock=\"%0.5f\",user=\"%0.5f\",system=\"%0.5f\"}", - timeval_diff (start->wallclock, end->wallclock) / 1000000.0, - timeval_diff (start->utime, end->utime) / 1000000.0, - timeval_diff (start->stime, end->stime) / 1000000.0); - } +{ + fprintf_unfiltered + (raw_stdout, + ",time={wallclock=\"%0.5f\",user=\"%0.5f\",system=\"%0.5f\"}", + timeval_diff (start->wallclock, end->wallclock) / 1000000.0, + timeval_diff (start->utime, end->utime) / 1000000.0, + timeval_diff (start->stime, end->stime) / 1000000.0); +} void mi_cmd_trace_define_variable (char *command, char **argv, int argc) { struct expression *expr; - struct cleanup *back_to; LONGEST initval = 0; struct trace_state_variable *tsv; char *name = 0; @@ -2341,19 +2364,11 @@ mi_cmd_trace_define_variable (char *command, char **argv, int argc) if (argc != 1 && argc != 2) error (_("Usage: -trace-define-variable VARIABLE [VALUE]")); - expr = parse_expression (argv[0]); - back_to = make_cleanup (xfree, expr); - - if (expr->nelts == 3 && expr->elts[0].opcode == OP_INTERNALVAR) - { - struct internalvar *intvar = expr->elts[1].internalvar; - - if (intvar) - name = internalvar_name (intvar); - } + name = argv[0]; + if (*name++ != '$') + error (_("Name of trace variable should start with '$'")); - if (!name || *name == '\0') - error (_("Invalid name of trace variable")); + validate_trace_state_variable_name (name); tsv = find_trace_state_variable (name); if (!tsv) @@ -2363,15 +2378,13 @@ mi_cmd_trace_define_variable (char *command, char **argv, int argc) initval = value_as_long (parse_and_eval (argv[1])); tsv->initial_value = initval; - - do_cleanups (back_to); } void mi_cmd_trace_list_variables (char *command, char **argv, int argc) { if (argc != 0) - error (_("-trace-list-variables: no arguments are allowed")); + error (_("-trace-list-variables: no arguments allowed")); tvariables_info_1 (); } @@ -2437,7 +2450,8 @@ mi_cmd_trace_find (char *command, char **argv, int argc) if (argc != 2) error (_("Line is required")); - sals = decode_line_spec (argv[1], DECODE_LINE_FUNFIRSTLINE); + sals = decode_line_with_current_source (argv[1], + DECODE_LINE_FUNFIRSTLINE); back_to = make_cleanup (xfree, sals.sals); sal = sals.sals[0]; @@ -2456,9 +2470,7 @@ mi_cmd_trace_find (char *command, char **argv, int argc) error (_("Invalid mode '%s'"), mode); if (has_stack_frames () || get_traceframe_number () >= 0) - { - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); - } + print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); } void @@ -2486,7 +2498,6 @@ mi_cmd_trace_save (char *command, char **argv, int argc) trace_save (filename, target_saves); } - void mi_cmd_trace_start (char *command, char **argv, int argc) { @@ -2506,7 +2517,7 @@ mi_cmd_trace_stop (char *command, char **argv, int argc) trace_status_mi (1); } -/* Implement the "-ada-task-info" GDB/MI command. */ +/* Implement the "-ada-task-info" command. */ void mi_cmd_ada_task_info (char *command, char **argv, int argc) diff --git a/contrib/gdb-7/gdb/mi/mi-main.h b/contrib/gdb-7/gdb/mi/mi-main.h index beac2cde97..d75526ac2e 100644 --- a/contrib/gdb-7/gdb/mi/mi-main.h +++ b/contrib/gdb-7/gdb/mi/mi-main.h @@ -1,6 +1,6 @@ /* MI Internal Functions for GDB, the GNU debugger. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -32,7 +32,19 @@ extern char *current_token; extern int running_result_record_printed; extern int mi_proceeded; -extern int mi_suppress_breakpoint_notifications; + +struct mi_suppress_notification +{ + /* Breakpoint notification suppressed? */ + int breakpoint; + /* Command param changed notification suppressed? */ + int cmd_param_changed; + /* Traceframe changed notification suppressed? */ + int traceframe; + /* Memory changed notification suppressed? */ + int memory; +}; +extern struct mi_suppress_notification mi_suppress_notification; #endif diff --git a/contrib/gdb-7/gdb/mi/mi-out.c b/contrib/gdb-7/gdb/mi/mi-out.c index f8f62257a9..90a4c1ce25 100644 --- a/contrib/gdb-7/gdb/mi/mi-out.c +++ b/contrib/gdb-7/gdb/mi/mi-out.c @@ -1,7 +1,6 @@ /* MI Command Set - output generating routines. - Copyright (C) 2000, 2002-2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -89,6 +88,7 @@ struct ui_out_impl mi_ui_out_impl = mi_wrap_hint, mi_flush, mi_redirect, + 0, 1, /* Needs MI hacks. */ }; @@ -100,7 +100,7 @@ static void mi_open (struct ui_out *uiout, const char *name, enum ui_out_type type); static void mi_close (struct ui_out *uiout, enum ui_out_type type); -/* Mark beginning of a table */ +/* Mark beginning of a table. */ void mi_table_begin (struct ui_out *uiout, @@ -109,14 +109,12 @@ mi_table_begin (struct ui_out *uiout, const char *tblid) { mi_open (uiout, tblid, ui_out_type_tuple); - mi_field_int (uiout, -1/*fldno*/, -1/*width*/, -1/*alin*/, - "nr_rows", nr_rows); - mi_field_int (uiout, -1/*fldno*/, -1/*width*/, -1/*alin*/, - "nr_cols", nr_cols); + mi_field_int (uiout, -1, -1, -1, "nr_rows", nr_rows); + mi_field_int (uiout, -1, -1, -1, "nr_cols", nr_cols); mi_open (uiout, "hdr", ui_out_type_list); } -/* Mark beginning of a table body */ +/* Mark beginning of a table body. */ void mi_table_body (struct ui_out *uiout) @@ -130,7 +128,7 @@ mi_table_body (struct ui_out *uiout) mi_open (uiout, "body", ui_out_type_list); } -/* Mark end of a table */ +/* Mark end of a table. */ void mi_table_end (struct ui_out *uiout) @@ -142,17 +140,17 @@ mi_table_end (struct ui_out *uiout) mi_close (uiout, ui_out_type_tuple); } -/* Specify table header */ +/* Specify table header. */ void mi_table_header (struct ui_out *uiout, int width, enum ui_align alignment, - const char *col_name, - const char *colhdr) + const char *col_name, const char *colhdr) { mi_out_data *data = ui_out_data (uiout); if (data->suppress_output) return; + mi_open (uiout, NULL, ui_out_type_tuple); mi_field_int (uiout, 0, 0, 0, "width", width); mi_field_int (uiout, 0, 0, 0, "alignment", alignment); @@ -161,38 +159,36 @@ mi_table_header (struct ui_out *uiout, int width, enum ui_align alignment, mi_close (uiout, ui_out_type_tuple); } -/* Mark beginning of a list */ +/* Mark beginning of a list. */ void -mi_begin (struct ui_out *uiout, - enum ui_out_type type, - int level, +mi_begin (struct ui_out *uiout, enum ui_out_type type, int level, const char *id) { mi_out_data *data = ui_out_data (uiout); if (data->suppress_output) return; + mi_open (uiout, id, type); } -/* Mark end of a list */ +/* Mark end of a list. */ void -mi_end (struct ui_out *uiout, - enum ui_out_type type, - int level) +mi_end (struct ui_out *uiout, enum ui_out_type type, int level) { mi_out_data *data = ui_out_data (uiout); if (data->suppress_output) return; + mi_close (uiout, type); } -/* output an int field */ +/* Output an int field. */ -void +static void mi_field_int (struct ui_out *uiout, int fldno, int width, enum ui_align alignment, const char *fldname, int value) { @@ -202,11 +198,11 @@ mi_field_int (struct ui_out *uiout, int fldno, int width, if (data->suppress_output) return; - sprintf (buffer, "%d", value); + xsnprintf (buffer, sizeof (buffer), "%d", value); mi_field_string (uiout, fldno, width, alignment, fldname, buffer); } -/* used to ommit a field */ +/* Used to omit a field. */ void mi_field_skip (struct ui_out *uiout, int fldno, int width, @@ -214,21 +210,18 @@ mi_field_skip (struct ui_out *uiout, int fldno, int width, { } -/* other specific mi_field_* end up here so alignment and field - separators are both handled by mi_field_string */ +/* Other specific mi_field_* end up here so alignment and field + separators are both handled by mi_field_string. */ void -mi_field_string (struct ui_out *uiout, - int fldno, - int width, - enum ui_align align, - const char *fldname, - const char *string) +mi_field_string (struct ui_out *uiout, int fldno, int width, + enum ui_align align, const char *fldname, const char *string) { mi_out_data *data = ui_out_data (uiout); if (data->suppress_output) return; + field_separator (uiout); if (fldname) fprintf_unfiltered (data->buffer, "%s=", fldname); @@ -238,19 +231,18 @@ mi_field_string (struct ui_out *uiout, fprintf_unfiltered (data->buffer, "\""); } -/* This is the only field function that does not align */ +/* This is the only field function that does not align. */ void -mi_field_fmt (struct ui_out *uiout, int fldno, - int width, enum ui_align align, - const char *fldname, - const char *format, - va_list args) +mi_field_fmt (struct ui_out *uiout, int fldno, int width, + enum ui_align align, const char *fldname, + const char *format, va_list args) { mi_out_data *data = ui_out_data (uiout); if (data->suppress_output) return; + field_separator (uiout); if (fldname) fprintf_unfiltered (data->buffer, "%s=\"", fldname); @@ -272,8 +264,7 @@ mi_text (struct ui_out *uiout, const char *string) void mi_message (struct ui_out *uiout, int verbosity, - const char *format, - va_list args) + const char *format, va_list args) { } @@ -326,9 +317,7 @@ field_separator (struct ui_out *uiout) } static void -mi_open (struct ui_out *uiout, - const char *name, - enum ui_out_type type) +mi_open (struct ui_out *uiout, const char *name, enum ui_out_type type) { mi_out_data *data = ui_out_data (uiout); @@ -350,8 +339,7 @@ mi_open (struct ui_out *uiout, } static void -mi_close (struct ui_out *uiout, - enum ui_out_type type) +mi_close (struct ui_out *uiout, enum ui_out_type type) { mi_out_data *data = ui_out_data (uiout); @@ -369,7 +357,7 @@ mi_close (struct ui_out *uiout, data->suppress_field_separator = 0; } -/* add a string to the buffer */ +/* Add a string to the buffer. */ void mi_out_buffered (struct ui_out *uiout, char *string) @@ -379,7 +367,7 @@ mi_out_buffered (struct ui_out *uiout, char *string) fprintf_unfiltered (data->buffer, "%s", string); } -/* clear the buffer */ +/* Clear the buffer. */ void mi_out_rewind (struct ui_out *uiout) @@ -389,7 +377,7 @@ mi_out_rewind (struct ui_out *uiout) ui_file_rewind (data->buffer); } -/* dump the buffer onto the specified stream */ +/* Dump the buffer onto the specified stream. */ static void do_write (void *data, const char *buffer, long length_buffer) @@ -398,8 +386,7 @@ do_write (void *data, const char *buffer, long length_buffer) } void -mi_out_put (struct ui_out *uiout, - struct ui_file *stream) +mi_out_put (struct ui_out *uiout, struct ui_file *stream) { mi_out_data *data = ui_out_data (uiout); @@ -407,7 +394,7 @@ mi_out_put (struct ui_out *uiout, ui_file_rewind (data->buffer); } -/* Current MI version. */ +/* Return the current MI version. */ int mi_version (struct ui_out *uiout) @@ -417,7 +404,7 @@ mi_version (struct ui_out *uiout) return data->mi_version; } -/* initalize private members at startup */ +/* Initialize private members at startup. */ struct ui_out * mi_out_new (int mi_version) @@ -433,10 +420,3 @@ mi_out_new (int mi_version) data->buffer = mem_fileopen (); return ui_out_new (&mi_ui_out_impl, data, flags); } - -/* standard gdb initialization hook */ -void -_initialize_mi_out (void) -{ - /* nothing happens here */ -} diff --git a/contrib/gdb-7/gdb/mi/mi-out.h b/contrib/gdb-7/gdb/mi/mi-out.h index d8763ad566..f5b8491979 100644 --- a/contrib/gdb-7/gdb/mi/mi-out.h +++ b/contrib/gdb-7/gdb/mi/mi-out.h @@ -1,5 +1,5 @@ /* MI Command Set - MI output generating routines for GDB. - Copyright (C) 2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. diff --git a/contrib/gdb-7/gdb/mi/mi-parse.c b/contrib/gdb-7/gdb/mi/mi-parse.c index 2fbfc382c1..15fb778946 100644 --- a/contrib/gdb-7/gdb/mi/mi-parse.c +++ b/contrib/gdb-7/gdb/mi/mi-parse.c @@ -1,6 +1,6 @@ /* MI Command Set - MI parser. - Copyright (C) 2000-2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -26,12 +26,13 @@ #include #include "gdb_string.h" +#include "cli/cli-utils.h" /* Like parse_escape, but leave the results as a host char, not a target char. */ static int -mi_parse_escape (char **string_ptr) +mi_parse_escape (const char **string_ptr) { int c = *(*string_ptr)++; @@ -102,9 +103,9 @@ mi_parse_escape (char **string_ptr) } static void -mi_parse_argv (char *args, struct mi_parse *parse) +mi_parse_argv (const char *args, struct mi_parse *parse) { - char *chp = args; + const char *chp = args; int argc = 0; char **argv = xmalloc ((argc + 1) * sizeof (char *)); @@ -113,9 +114,8 @@ mi_parse_argv (char *args, struct mi_parse *parse) { char *arg; - /* skip leading white space */ - while (isspace (*chp)) - chp++; + /* Skip leading white space. */ + chp = skip_spaces_const (chp); /* Three possibilities: EOF, quoted string, or other text. */ switch (*chp) { @@ -125,11 +125,11 @@ mi_parse_argv (char *args, struct mi_parse *parse) return; case '"': { - /* A quoted string. */ + /* A quoted string. */ int len; - char *start = chp + 1; + const char *start = chp + 1; - /* Determine the buffer size. */ + /* Determine the buffer size. */ chp = start; len = 0; while (*chp != '\0' && *chp != '"') @@ -139,7 +139,7 @@ mi_parse_argv (char *args, struct mi_parse *parse) chp++; if (mi_parse_escape (&chp) <= 0) { - /* Do not allow split lines or "\000" */ + /* Do not allow split lines or "\000". */ freeargv (argv); return; } @@ -148,21 +148,20 @@ mi_parse_argv (char *args, struct mi_parse *parse) chp++; len++; } - /* Insist on a closing quote. */ + /* Insist on a closing quote. */ if (*chp != '"') { freeargv (argv); return; } - /* Insist on trailing white space. */ + /* Insist on trailing white space. */ if (chp[1] != '\0' && !isspace (chp[1])) { freeargv (argv); return; } - /* create the buffer. */ + /* Create the buffer and copy characters in. */ arg = xmalloc ((len + 1) * sizeof (char)); - /* And copy the characters in. */ chp = start; len = 0; while (*chp != '\0' && *chp != '"') @@ -177,15 +176,15 @@ mi_parse_argv (char *args, struct mi_parse *parse) len++; } arg[len] = '\0'; - chp++; /* that closing quote. */ + chp++; /* That closing quote. */ break; } default: { - /* An unquoted string. Accumulate all non blank - characters into a buffer. */ + /* An unquoted string. Accumulate all non-blank + characters into a buffer. */ int len; - char *start = chp; + const char *start = chp; while (*chp != '\0' && !isspace (*chp)) { @@ -198,14 +197,13 @@ mi_parse_argv (char *args, struct mi_parse *parse) break; } } - /* Append arg to argv. */ + /* Append arg to argv. */ argv = xrealloc (argv, (argc + 2) * sizeof (char *)); argv[argc++] = arg; argv[argc] = NULL; } } - void mi_parse_free (struct mi_parse *parse) { @@ -231,9 +229,9 @@ mi_parse_cleanup (void *arg) } struct mi_parse * -mi_parse (char *cmd, char **token) +mi_parse (const char *cmd, char **token) { - char *chp; + const char *chp; struct mi_parse *parse = XMALLOC (struct mi_parse); struct cleanup *cleanup; @@ -245,22 +243,20 @@ mi_parse (char *cmd, char **token) cleanup = make_cleanup (mi_parse_cleanup, parse); - /* Before starting, skip leading white space. */ - while (isspace (*cmd)) - cmd++; + /* Before starting, skip leading white space. */ + cmd = skip_spaces_const (cmd); - /* Find/skip any token and then extract it. */ + /* Find/skip any token and then extract it. */ for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++) ; *token = xmalloc (chp - cmd + 1); memcpy (*token, cmd, (chp - cmd)); (*token)[chp - cmd] = '\0'; - /* This wasn't a real MI command. Return it as a CLI_COMMAND. */ + /* This wasn't a real MI command. Return it as a CLI_COMMAND. */ if (*chp != '-') { - while (isspace (*chp)) - chp++; + chp = skip_spaces_const (chp); parse->command = xstrdup (chp); parse->op = CLI_COMMAND; @@ -269,9 +265,9 @@ mi_parse (char *cmd, char **token) return parse; } - /* Extract the command. */ + /* Extract the command. */ { - char *tmp = chp + 1; /* discard ``-'' */ + const char *tmp = chp + 1; /* discard ``-'' */ for (; *chp && !isspace (*chp); chp++) ; @@ -280,20 +276,19 @@ mi_parse (char *cmd, char **token) parse->command[chp - tmp] = '\0'; } - /* Find the command in the MI table. */ + /* Find the command in the MI table. */ parse->cmd = mi_lookup (parse->command); if (parse->cmd == NULL) error (_("Undefined MI command: %s"), parse->command); - /* Skip white space following the command. */ - while (isspace (*chp)) - chp++; + /* Skip white space following the command. */ + chp = skip_spaces_const (chp); /* Parse the --thread and --frame options, if present. At present, - some important commands, like '-break-*' are implemented by forwarding - to the CLI layer directly. We want to parse --thread and --frame - here, so as not to leave those option in the string that will be passed - to CLI. */ + some important commands, like '-break-*' are implemented by + forwarding to the CLI layer directly. We want to parse --thread + and --frame here, so as not to leave those option in the string + that will be passed to CLI. */ for (;;) { const char *option; @@ -315,6 +310,8 @@ mi_parse (char *cmd, char **token) } if (strncmp (chp, "--thread-group ", tgs) == 0) { + char *endp; + option = "--thread-group"; if (parse->thread_group != -1) error (_("Duplicate '--thread-group' option")); @@ -322,35 +319,41 @@ mi_parse (char *cmd, char **token) if (*chp != 'i') error (_("Invalid thread group id")); chp += 1; - parse->thread_group = strtol (chp, &chp, 10); + parse->thread_group = strtol (chp, &endp, 10); + chp = endp; } else if (strncmp (chp, "--thread ", ts) == 0) { + char *endp; + option = "--thread"; if (parse->thread != -1) error (_("Duplicate '--thread' option")); chp += ts; - parse->thread = strtol (chp, &chp, 10); + parse->thread = strtol (chp, &endp, 10); + chp = endp; } else if (strncmp (chp, "--frame ", fs) == 0) { + char *endp; + option = "--frame"; if (parse->frame != -1) error (_("Duplicate '--frame' option")); chp += fs; - parse->frame = strtol (chp, &chp, 10); + parse->frame = strtol (chp, &endp, 10); + chp = endp; } else break; if (*chp != '\0' && !isspace (*chp)) error (_("Invalid value for the '%s' option"), option); - while (isspace (*chp)) - chp++; + chp = skip_spaces_const (chp); } /* For new argv commands, attempt to return the parsed argument - list. */ + list. */ if (parse->cmd->argv_func != NULL) { mi_parse_argv (chp, parse); @@ -366,7 +369,7 @@ mi_parse (char *cmd, char **token) discard_cleanups (cleanup); - /* Fully parsed. */ + /* Fully parsed, flag as an MI command. */ parse->op = MI_COMMAND; return parse; } diff --git a/contrib/gdb-7/gdb/mi/mi-parse.h b/contrib/gdb-7/gdb/mi/mi-parse.h index 59e57de5a7..324ae5d913 100644 --- a/contrib/gdb-7/gdb/mi/mi-parse.h +++ b/contrib/gdb-7/gdb/mi/mi-parse.h @@ -1,5 +1,5 @@ /* MI Command Set - MI Command Parser. - Copyright (C) 2000, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. @@ -60,9 +60,9 @@ struct mi_parse the TOKEN field of the resultant mi_parse object, to be freed by mi_parse_free. */ -extern struct mi_parse *mi_parse (char *cmd, char **token); +extern struct mi_parse *mi_parse (const char *cmd, char **token); -/* Free a command returned by mi_parse_command. */ +/* Free a command returned by mi_parse_command. */ extern void mi_parse_free (struct mi_parse *cmd); diff --git a/contrib/gdb-7/gdb/mi/mi-symbol-cmds.c b/contrib/gdb-7/gdb/mi/mi-symbol-cmds.c index 7feb02435d..e4aa83e64c 100644 --- a/contrib/gdb-7/gdb/mi/mi-symbol-cmds.c +++ b/contrib/gdb-7/gdb/mi/mi-symbol-cmds.c @@ -1,5 +1,5 @@ /* MI Command Set - symbol commands. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,11 +22,9 @@ #include "objfiles.h" #include "ui-out.h" -/* SYMBOL-LIST-LINES: - - Print the list of all pc addresses and lines of code for - the provided (full or base) source file name. The entries - are sorted in ascending PC order. */ +/* Print the list of all pc addresses and lines of code for the + provided (full or base) source file name. The entries are sorted + in ascending PC order. */ void mi_cmd_symbol_list_lines (char *command, char **argv, int argc) @@ -47,9 +45,9 @@ mi_cmd_symbol_list_lines (char *command, char **argv, int argc) if (s == NULL) error (_("-symbol-list-lines: Unknown source file name.")); - /* Now, dump the associated line table. The pc addresses are already - sorted by increasing values in the symbol table, so no need to - perform any other sorting. */ + /* Now, dump the associated line table. The pc addresses are + already sorted by increasing values in the symbol table, so no + need to perform any other sorting. */ gdbarch = get_objfile_arch (s->objfile); cleanup_stack = make_cleanup_ui_out_list_begin_end (uiout, "lines"); diff --git a/contrib/gdb-7/gdb/minidebug.c b/contrib/gdb-7/gdb/minidebug.c new file mode 100644 index 0000000000..a33628a18b --- /dev/null +++ b/contrib/gdb-7/gdb/minidebug.c @@ -0,0 +1,290 @@ +/* Read MiniDebugInfo data from an objfile. + + Copyright (C) 2012-2013 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 "gdb_bfd.h" +#include "gdb_string.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" + +#ifdef HAVE_LIBLZMA + +#include + +/* Allocator function for LZMA. */ + +static void * +alloc_lzma (void *opaque, size_t nmemb, size_t size) +{ + return xmalloc (nmemb * size); +} + +/* Free function for LZMA. */ + +static void +free_lzma (void *opaque, void *ptr) +{ + xfree (ptr); +} + +/* The allocator object for LZMA. Note that 'gdb_lzma_allocator' + cannot be const due to the lzma library function prototypes. */ + +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL }; + +/* Custom bfd_openr_iovec implementation to read compressed data from + a section. This keeps only the last decompressed block in memory + to allow larger data without using to much memory. */ + +struct lzma_stream +{ + /* Section of input BFD from which we are decoding data. */ + asection *section; + + /* lzma library decompression state. */ + lzma_index *index; + + /* Currently decoded block. */ + bfd_size_type data_start; + bfd_size_type data_end; + gdb_byte *data; +}; + +/* bfd_openr_iovec OPEN_P implementation for + find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' + of the section to decompress. + + Return 'struct lzma_stream *' must be freed by caller by xfree, together + with its INDEX lzma data. */ + +static void * +lzma_open (struct bfd *nbfd, void *open_closure) +{ + asection *section = open_closure; + bfd_size_type size, offset; + lzma_stream_flags options; + gdb_byte footer[LZMA_STREAM_HEADER_SIZE]; + gdb_byte *indexdata; + lzma_index *index; + int ret; + uint64_t memlimit = UINT64_MAX; + struct lzma_stream *lstream; + size_t pos; + + size = bfd_get_section_size (section); + offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE; + if (size < LZMA_STREAM_HEADER_SIZE + || bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner) + != LZMA_STREAM_HEADER_SIZE + || lzma_stream_footer_decode (&options, footer) != LZMA_OK + || offset < options.backward_size) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + offset -= options.backward_size; + indexdata = xmalloc (options.backward_size); + index = NULL; + pos = 0; + if (bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (indexdata, options.backward_size, section->owner) + != options.backward_size + || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator, + indexdata, &pos, options.backward_size) + != LZMA_OK + || lzma_index_size (index) != options.backward_size) + { + xfree (indexdata); + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + xfree (indexdata); + + lstream = xzalloc (sizeof (struct lzma_stream)); + lstream->section = section; + lstream->index = index; + + return lstream; +} + +/* bfd_openr_iovec PREAD_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static file_ptr +lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes, + file_ptr offset) +{ + struct lzma_stream *lstream = stream; + bfd_size_type chunk_size; + lzma_index_iter iter; + gdb_byte *compressed, *uncompressed; + file_ptr block_offset; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_block block; + size_t compressed_pos, uncompressed_pos; + file_ptr res; + + res = 0; + while (nbytes > 0) + { + if (lstream->data == NULL + || lstream->data_start > offset || offset >= lstream->data_end) + { + asection *section = lstream->section; + + lzma_index_iter_init (&iter, lstream->index); + if (lzma_index_iter_locate (&iter, offset)) + break; + + compressed = xmalloc (iter.block.total_size); + block_offset = section->filepos + iter.block.compressed_file_offset; + if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0 + || bfd_bread (compressed, iter.block.total_size, section->owner) + != iter.block.total_size) + { + xfree (compressed); + break; + } + + uncompressed = xmalloc (iter.block.uncompressed_size); + + memset (&block, 0, sizeof (block)); + block.filters = filters; + block.header_size = lzma_block_header_size_decode (compressed[0]); + if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + compressed_pos = block.header_size; + uncompressed_pos = 0; + if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator, + compressed, &compressed_pos, + iter.block.total_size, + uncompressed, &uncompressed_pos, + iter.block.uncompressed_size) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + xfree (compressed); + + xfree (lstream->data); + lstream->data = uncompressed; + lstream->data_start = iter.block.uncompressed_file_offset; + lstream->data_end = (iter.block.uncompressed_file_offset + + iter.block.uncompressed_size); + } + + chunk_size = min (nbytes, lstream->data_end - offset); + memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size); + buf = (gdb_byte *) buf + chunk_size; + offset += chunk_size; + nbytes -= chunk_size; + res += chunk_size; + } + + return res; +} + +/* bfd_openr_iovec CLOSE_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_close (struct bfd *nbfd, + void *stream) +{ + struct lzma_stream *lstream = stream; + + lzma_index_end (lstream->index, &gdb_lzma_allocator); + xfree (lstream->data); + xfree (lstream); + + /* Zero means success. */ + return 0; +} + +/* bfd_openr_iovec STAT_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_stat (struct bfd *abfd, + void *stream, + struct stat *sb) +{ + struct lzma_stream *lstream = stream; + + sb->st_size = lzma_index_uncompressed_size (lstream->index); + return 0; +} + +#endif /* HAVE_LIBLZMA */ + +/* This looks for a xz compressed separate debug info object file embedded + in a section called .gnu_debugdata. See + http://fedoraproject.org/wiki/Features/MiniDebugInfo + or the "Separate Debug Sections" of the manual for details. + If we find one we create a iovec based bfd that decompresses the + object data on demand. If we don't find one, return NULL. */ + +bfd * +find_separate_debug_file_in_section (struct objfile *objfile) +{ + asection *section; + bfd *abfd; + + if (objfile->obfd == NULL) + return NULL; + + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); + if (section == NULL) + return NULL; + +#ifdef HAVE_LIBLZMA + abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section, + lzma_pread, lzma_close, lzma_stat); + if (abfd == NULL) + return NULL; + + if (!bfd_check_format (abfd, bfd_object)) + { + warning (_("Cannot parse .gnu_debugdata section; not a BFD object")); + gdb_bfd_unref (abfd); + return NULL; + } +#else + warning (_("Cannot parse .gnu_debugdata section; LZMA support was " + "disabled at compile time")); + abfd = NULL; +#endif /* !HAVE_LIBLZMA */ + + return abfd; +} diff --git a/contrib/gdb-7/gdb/minsyms.c b/contrib/gdb-7/gdb/minsyms.c index 2aec6324d0..059b70a6dc 100644 --- a/contrib/gdb-7/gdb/minsyms.c +++ b/contrib/gdb-7/gdb/minsyms.c @@ -1,5 +1,5 @@ /* GDB routines for manipulating the minimal symbol tables. - Copyright (C) 1992-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. Contributed by Cygnus Support, using pieces from other GDB modules. This file is part of GDB. @@ -50,6 +50,7 @@ #include "target.h" #include "cp-support.h" #include "language.h" +#include "cli/cli-utils.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 @@ -76,7 +77,7 @@ static int msym_bunch_index; static int msym_count; -/* Compute a hash code based using the same criteria as `strcmp_iw'. */ +/* See minsyms.h. */ unsigned int msymbol_hash_iw (const char *string) @@ -85,8 +86,7 @@ msymbol_hash_iw (const char *string) while (*string && *string != '(') { - while (isspace (*string)) - ++string; + string = skip_spaces_const (string); if (*string && *string != '(') { hash = SYMBOL_HASH_NEXT (hash, *string); @@ -96,7 +96,7 @@ msymbol_hash_iw (const char *string) return hash; } -/* Compute a hash code for a string. */ +/* See minsyms.h. */ unsigned int msymbol_hash (const char *string) @@ -109,7 +109,7 @@ msymbol_hash (const char *string) } /* Add the minimal symbol SYM to an objfile's minsym hash table, TABLE. */ -void +static void add_minsym_to_hash_table (struct minimal_symbol *sym, struct minimal_symbol **table) { @@ -139,8 +139,8 @@ add_minsym_to_demangled_hash_table (struct minimal_symbol *sym, } } +/* See minsyms.h. */ -/* Return OBJFILE where minimal symbol SYM is defined. */ struct objfile * msymbol_objfile (struct minimal_symbol *sym) { @@ -308,13 +308,7 @@ lookup_minimal_symbol (const char *name, const char *sfile, return NULL; } -/* Iterate over all the minimal symbols in the objfile OBJF which - match NAME. Both the ordinary and demangled names of each symbol - are considered. The caller is responsible for canonicalizing NAME, - should that need to be done. - - For each matching symbol, CALLBACK is called with the symbol and - USER_DATA as arguments. */ +/* See minsyms.h. */ void iterate_over_minimal_symbols (struct objfile *objf, const char *name, @@ -348,12 +342,7 @@ iterate_over_minimal_symbols (struct objfile *objf, const char *name, } } -/* Look through all the current minimal symbol tables and find the - first minimal symbol that matches NAME and has text type. If OBJF - is non-NULL, limit the search to that objfile. Returns a pointer - to the minimal symbol that matches, or NULL if no match is found. - - This function only searches the mangled (linkage) names. */ +/* See minsyms.h. */ struct minimal_symbol * lookup_minimal_symbol_text (const char *name, struct objfile *objf) @@ -405,10 +394,7 @@ lookup_minimal_symbol_text (const char *name, struct objfile *objf) return NULL; } -/* Look through all the current minimal symbol tables and find the - first minimal symbol that matches NAME and PC. If OBJF is non-NULL, - limit the search to that objfile. Returns a pointer to the minimal - symbol that matches, or NULL if no match is found. */ +/* See minsyms.h. */ struct minimal_symbol * lookup_minimal_symbol_by_pc_name (CORE_ADDR pc, const char *name, @@ -440,13 +426,7 @@ lookup_minimal_symbol_by_pc_name (CORE_ADDR pc, const char *name, return NULL; } -/* Look through all the current minimal symbol tables and find the - first minimal symbol that matches NAME and is a solib trampoline. - If OBJF is non-NULL, limit the search to that objfile. Returns a - pointer to the minimal symbol that matches, or NULL if no match is - found. - - This function only searches the mangled (linkage) names. */ +/* See minsyms.h. */ struct minimal_symbol * lookup_minimal_symbol_solib_trampoline (const char *name, @@ -732,8 +712,7 @@ lookup_minimal_symbol_by_pc_section (CORE_ADDR pc, struct obj_section *section) return lookup_minimal_symbol_by_pc_section_1 (pc, section, 0); } -/* Backward compatibility: search through the minimal symbol table - for a matching PC (no section given). */ +/* See minsyms.h. */ struct minimal_symbol * lookup_minimal_symbol_by_pc (CORE_ADDR pc) @@ -804,10 +783,7 @@ static const struct gnu_ifunc_fns stub_gnu_ifunc_fns = const struct gnu_ifunc_fns *gnu_ifunc_fns_p = &stub_gnu_ifunc_fns; -/* Find the minimal symbol named NAME, and return both the minsym - struct and its objfile. This only checks the linkage name. Sets - *OBJFILE_P and returns the minimal symbol, if it is found. If it - is not found, returns NULL. */ +/* See minsyms.h. */ struct minimal_symbol * lookup_minimal_symbol_and_objfile (const char *name, @@ -851,18 +827,21 @@ get_symbol_leading_char (bfd *abfd) return 0; } -/* Prepare to start collecting minimal symbols. Note that presetting - msym_bunch_index to BUNCH_SIZE causes the first call to save a minimal - symbol to allocate the memory for the first bunch. */ +/* See minsyms.h. */ void init_minimal_symbol_collection (void) { msym_count = 0; msym_bunch = NULL; + /* Note that presetting msym_bunch_index to BUNCH_SIZE causes the + first call to save a minimal symbol to allocate the memory for + the first bunch. */ msym_bunch_index = BUNCH_SIZE; } +/* See minsyms.h. */ + void prim_record_minimal_symbol (const char *name, CORE_ADDR address, enum minimal_symbol_type ms_type, @@ -894,8 +873,7 @@ prim_record_minimal_symbol (const char *name, CORE_ADDR address, section, NULL, objfile); } -/* Record a minimal symbol in the msym bunches. Returns the symbol - newly created. */ +/* See minsyms.h. */ struct minimal_symbol * prim_record_minimal_symbol_full (const char *name, int name_len, int copy_name, @@ -959,7 +937,9 @@ prim_record_minimal_symbol_full (const char *name, int name_len, int copy_name, MSYMBOL_TYPE (msymbol) = ms_type; MSYMBOL_TARGET_FLAG_1 (msymbol) = 0; MSYMBOL_TARGET_FLAG_2 (msymbol) = 0; - MSYMBOL_SIZE (msymbol) = 0; + /* Do not use the SET_MSYMBOL_SIZE macro to initialize the size, + as it would also set the has_size flag. */ + msymbol->size = 0; /* The hash pointers must be cleared! If they're not, add_minsym_to_hash_table will NOT add this msymbol to the hash table. */ @@ -972,8 +952,7 @@ prim_record_minimal_symbol_full (const char *name, int name_len, int copy_name, return msymbol; } -/* Record a minimal symbol in the msym bunches. Returns the symbol - newly created. */ +/* See minsyms.h. */ struct minimal_symbol * prim_record_minimal_symbol_and_info (const char *name, CORE_ADDR address, @@ -1011,8 +990,8 @@ compare_minimal_symbols (const void *fn1p, const void *fn2p) else /* addrs are equal: sort by name */ { - char *name1 = SYMBOL_LINKAGE_NAME (fn1); - char *name2 = SYMBOL_LINKAGE_NAME (fn2); + const char *name1 = SYMBOL_LINKAGE_NAME (fn1); + const char *name2 = SYMBOL_LINKAGE_NAME (fn2); if (name1 && name2) /* both have names */ return strcmp (name1, name2); @@ -1046,6 +1025,8 @@ do_discard_minimal_symbols_cleanup (void *arg) } } +/* See minsyms.h. */ + struct cleanup * make_cleanup_discard_minimal_symbols (void) { @@ -1188,6 +1169,13 @@ install_minimal_symbols (struct objfile *objfile) if (msym_count > 0) { + if (symtab_create_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Installing %d minimal symbols of objfile %s.\n", + msym_count, objfile->name); + } + /* Allocate enough space in the obstack, into which we will gather the bunches of new and existing minimal symbols, sort them, and then compact out the duplicate entries. Once we have a final table, @@ -1243,13 +1231,7 @@ install_minimal_symbols (struct objfile *objfile) symbol count does *not* include this null symbol, which is why it is indexed by mcount and not mcount-1. */ - SYMBOL_LINKAGE_NAME (&msymbols[mcount]) = NULL; - SYMBOL_VALUE_ADDRESS (&msymbols[mcount]) = 0; - MSYMBOL_TARGET_FLAG_1 (&msymbols[mcount]) = 0; - MSYMBOL_TARGET_FLAG_2 (&msymbols[mcount]) = 0; - MSYMBOL_SIZE (&msymbols[mcount]) = 0; - MSYMBOL_TYPE (&msymbols[mcount]) = mst_unknown; - SYMBOL_SET_LANGUAGE (&msymbols[mcount], language_unknown); + memset (&msymbols[mcount], 0, sizeof (struct minimal_symbol)); /* Attach the minimal symbol table to the specified objfile. The strings themselves are also located in the objfile_obstack @@ -1258,29 +1240,6 @@ install_minimal_symbols (struct objfile *objfile) objfile->minimal_symbol_count = mcount; objfile->msymbols = msymbols; - /* Try to guess the appropriate C++ ABI by looking at the names - of the minimal symbols in the table. */ - { - int i; - - for (i = 0; i < mcount; i++) - { - /* If a symbol's name starts with _Z and was successfully - demangled, then we can assume we've found a GNU v3 symbol. - For now we set the C++ ABI globally; if the user is - mixing ABIs then the user will need to "set cp-abi" - manually. */ - const char *name = SYMBOL_LINKAGE_NAME (&objfile->msymbols[i]); - - if (name[0] == '_' && name[1] == 'Z' - && SYMBOL_DEMANGLED_NAME (&objfile->msymbols[i]) != NULL) - { - set_cp_abi_as_auto_default ("gnu-v3"); - break; - } - } - } - /* Now build the hash tables; we can't do this incrementally at an earlier point since we weren't finished with the obstack yet. (And if the msymbol obstack gets moved, all the internal @@ -1289,6 +1248,27 @@ install_minimal_symbols (struct objfile *objfile) } } +/* See minsyms.h. */ + +void +terminate_minimal_symbol_table (struct objfile *objfile) +{ + if (! objfile->msymbols) + objfile->msymbols = ((struct minimal_symbol *) + obstack_alloc (&objfile->objfile_obstack, + sizeof (objfile->msymbols[0]))); + + { + struct minimal_symbol *m + = &objfile->msymbols[objfile->minimal_symbol_count]; + + memset (m, 0, sizeof (*m)); + /* Don't rely on these enumeration values being 0's. */ + MSYMBOL_TYPE (m) = mst_unknown; + SYMBOL_SET_LANGUAGE (m, language_unknown); + } +} + /* Sort all the minimal symbols in OBJFILE. */ void @@ -1303,7 +1283,7 @@ msymbols_sort (struct objfile *objfile) Return minimal symbol for the trampoline entry or NULL if PC is not in a trampoline code stub. */ -struct minimal_symbol * +static struct minimal_symbol * lookup_solib_trampoline_symbol_by_pc (CORE_ADDR pc) { struct obj_section *section = find_pc_section (pc); diff --git a/contrib/gdb-7/gdb/minsyms.h b/contrib/gdb-7/gdb/minsyms.h new file mode 100644 index 0000000000..e3980ea6c4 --- /dev/null +++ b/contrib/gdb-7/gdb/minsyms.h @@ -0,0 +1,245 @@ +/* Minimal symbol table definitions for GDB. + + Copyright (C) 2011-2013 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 MINSYMS_H +#define MINSYMS_H + +/* This header declares most of the API for dealing with minimal + symbols and minimal symbol tables. A few things are declared + elsewhere; see below. + + A minimal symbol is a symbol for which there is no direct debug + information. For example, for an ELF binary, minimal symbols are + created from the ELF symbol table. + + For the definition of the minimal symbol structure, see struct + minimal_symbol in symtab.h. + + Minimal symbols are stored in tables attached to an objfile; see + objfiles.h for details. Code should generally treat these tables + as opaque and use functions provided by minsyms.c to inspect them. +*/ + +/* Prepare to start collecting minimal symbols. This should be called + by a symbol reader to initialize the minimal symbol module. + Currently, minimal symbol table creation is not reentrant; it + relies on global (static) variables in minsyms.c. */ + +void init_minimal_symbol_collection (void); + +/* Return a cleanup which is used to clean up the global state left + over by minimal symbol creation. After calling + init_minimal_symbol_collection, a symbol reader should call this + function. Then, after all minimal symbols have been read, + regardless of whether they are installed or not, the cleanup + returned by this function should be run. */ + +struct cleanup *make_cleanup_discard_minimal_symbols (void); + +/* Record a new minimal symbol. This is the "full" entry point; + simpler convenience entry points are also provided below. + + This returns a new minimal symbol. It is ok to modify the returned + minimal symbol (though generally not necessary). It is not ok, + though, to stash the pointer anywhere; as minimal symbols may be + moved after creation. The memory for the returned minimal symbol + is still owned by the minsyms.c code, and should not be freed. + + Arguments are: + + NAME - the symbol's name + NAME_LEN - the length of the name + COPY_NAME - if true, the minsym code must make a copy of NAME. If + false, then NAME must be NUL-terminated, and must have a lifetime + that is at least as long as OBJFILE's lifetime. + ADDRESS - the address of the symbol + MS_TYPE - the type of the symbol + SECTION - the symbol's section + BFD_SECTION - the symbol's BFD section; used to find the + appropriate obj_section for the minimal symbol. This can be NULL. + OBJFILE - the objfile associated with the minimal symbol. */ + +struct minimal_symbol *prim_record_minimal_symbol_full + (const char *name, + int name_len, + int copy_name, + CORE_ADDR address, + enum minimal_symbol_type ms_type, + int section, + asection *bfd_section, + struct objfile *objfile); + +/* Like prim_record_minimal_symbol_full, but: + - uses strlen to compute NAME_LEN, + - passes COPY_NAME = 0, + - passes SECTION = 0, + - and passes BFD_SECTION = NULL. + + This variant does not return the new symbol. */ + +void prim_record_minimal_symbol (const char *, CORE_ADDR, + enum minimal_symbol_type, + struct objfile *); + +/* Like prim_record_minimal_symbol_full, but: + - uses strlen to compute NAME_LEN, + - passes COPY_NAME = 0. */ + +struct minimal_symbol *prim_record_minimal_symbol_and_info + (const char *, + CORE_ADDR, + enum minimal_symbol_type, + int section, + asection *bfd_section, + struct objfile *); + +/* Install the minimal symbols that have been collected into the given + objfile. After this is called, the cleanup returned by + make_cleanup_discard_minimal_symbols should be run in order to + clean up global state. */ + +void install_minimal_symbols (struct objfile *); + +/* Create the terminating entry of OBJFILE's minimal symbol table. + If OBJFILE->msymbols is zero, allocate a single entry from + OBJFILE->objfile_obstack; otherwise, just initialize + OBJFILE->msymbols[OBJFILE->minimal_symbol_count]. */ + +void terminate_minimal_symbol_table (struct objfile *objfile); + +/* Sort all the minimal symbols in OBJFILE. This should be only be + called after relocating symbols; it ensures that the minimal + symbols are properly sorted by address. */ + +void msymbols_sort (struct objfile *objfile); + + + +/* Compute a hash code for the string argument. */ + +unsigned int msymbol_hash (const char *); + +/* Like msymbol_hash, but compute a hash code that is compatible with + strcmp_iw. */ + +unsigned int msymbol_hash_iw (const char *); + +/* Compute the next hash value from previous HASH and the character C. This + is only a GDB in-memory computed value with no external files compatibility + requirements. */ + +#define SYMBOL_HASH_NEXT(hash, c) \ + ((hash) * 67 + tolower ((unsigned char) (c)) - 113) + + + +/* Return the objfile that holds the minimal symbol SYM. Every + minimal symbols is held by some objfile; this will never return + NULL. */ + +struct objfile *msymbol_objfile (struct minimal_symbol *sym); + + + +/* Look through all the current minimal symbol tables and find the + first minimal symbol that matches NAME. If OBJF is non-NULL, limit + the search to that objfile. If SFILE is non-NULL, the only file-scope + symbols considered will be from that source file (global symbols are + still preferred). Returns a pointer to the minimal symbol that + matches, or NULL if no match is found. */ + +struct minimal_symbol *lookup_minimal_symbol (const char *, + const char *, + struct objfile *); + +/* Find the minimal symbol named NAME, and return both the minsym + struct and its objfile. This only checks the linkage name. Sets + *OBJFILE_P and returns the minimal symbol, if it is found. If it + is not found, returns NULL. */ + +struct minimal_symbol *lookup_minimal_symbol_and_objfile (const char *, + struct objfile **); + +/* Look through all the current minimal symbol tables and find the + first minimal symbol that matches NAME and has text type. If OBJF + is non-NULL, limit the search to that objfile. Returns a pointer + to the minimal symbol that matches, or NULL if no match is found. + + This function only searches the mangled (linkage) names. */ + +struct minimal_symbol *lookup_minimal_symbol_text (const char *, + struct objfile *); + +/* Look through all the current minimal symbol tables and find the + first minimal symbol that matches NAME and is a solib trampoline. + If OBJF is non-NULL, limit the search to that objfile. Returns a + pointer to the minimal symbol that matches, or NULL if no match is + found. + + This function only searches the mangled (linkage) names. */ + +struct minimal_symbol *lookup_minimal_symbol_solib_trampoline + (const char *, + struct objfile *); + +/* Look through all the current minimal symbol tables and find the + first minimal symbol that matches NAME and PC. If OBJF is non-NULL, + limit the search to that objfile. Returns a pointer to the minimal + symbol that matches, or NULL if no match is found. */ + +struct minimal_symbol *lookup_minimal_symbol_by_pc_name + (CORE_ADDR, const char *, struct objfile *); + +/* Search through the minimal symbol table for each objfile and find + the symbol whose address is the largest address that is still less + than or equal to PC, and which matches SECTION. + + If SECTION is NULL, this uses the result of find_pc_section + instead. + + Returns a pointer to the minimal symbol if such a symbol is found, + or NULL if PC is not in a suitable range. */ + +struct minimal_symbol *lookup_minimal_symbol_by_pc_section + (CORE_ADDR, + struct obj_section *); + +/* Backward compatibility: search through the minimal symbol table + for a matching PC (no section given). + + This is a wrapper that calls lookup_minimal_symbol_by_pc_section + with a NULL section argument. */ + +struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR); + +/* Iterate over all the minimal symbols in the objfile OBJF which + match NAME. Both the ordinary and demangled names of each symbol + are considered. The caller is responsible for canonicalizing NAME, + should that need to be done. + + For each matching symbol, CALLBACK is called with the symbol and + USER_DATA as arguments. */ + +void iterate_over_minimal_symbols (struct objfile *objf, + const char *name, + void (*callback) (struct minimal_symbol *, + void *), + void *user_data); + +#endif /* MINSYMS_H */ diff --git a/contrib/gdb-7/gdb/mipsread.c b/contrib/gdb-7/gdb/mipsread.c index 5790730f3f..e9f0402458 100644 --- a/contrib/gdb-7/gdb/mipsread.c +++ b/contrib/gdb-7/gdb/mipsread.c @@ -1,7 +1,6 @@ /* Read a symbol table in MIPS' format (Third-Eye). - Copyright (C) 1986-1987, 1989-1996, 1998-2001, 2003-2004, 2007-2012 - Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. Contributed by Alessandro Forin (af@cs.cmu.edu) at CMU. Major work by Per Bothner, John Gilmore and Ian Lance Taylor at Cygnus Support. @@ -401,6 +400,7 @@ static const struct sym_fns ecoff_sym_fns = default_symfile_segments, /* Get segment information from a file. */ NULL, default_symfile_relocate, /* Relocate a debug section. */ + NULL, /* sym_probe_fns */ &psym_functions }; diff --git a/contrib/gdb-7/gdb/objc-exp.y b/contrib/gdb-7/gdb/objc-exp.y deleted file mode 100644 index 346b404181..0000000000 --- a/contrib/gdb-7/gdb/objc-exp.y +++ /dev/null @@ -1,1787 +0,0 @@ -/* YACC parser for C expressions, for GDB. - - Copyright (C) 1986, 1989-1991, 1993-1994, 2002, 2006-2012 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 . */ - -/* Parse a C expression from text in a string, and return the result - as a struct expression pointer. That structure contains arithmetic - operations in reverse polish, with constants represented by - operations that are followed by special data. See expression.h for - the details of the format. What is important here is that it can - be built up sequentially during the process of parsing; the lower - levels of the tree always come first in the result. - - Note that malloc's and realloc's in this file are transformed to - xmalloc and xrealloc respectively by the same sed command in the - makefile that remaps any other malloc/realloc inserted by the - parser generator. Doing this with #defines and trying to control - the interaction with include files ( and for - example) just became too messy, particularly when such includes can - be inserted at random times by the parser generator. */ - -%{ - -#include "defs.h" -#include "gdb_string.h" -#include -#include "expression.h" - -#include "objc-lang.h" /* For objc language constructs. */ - -#include "value.h" -#include "parser-defs.h" -#include "language.h" -#include "c-lang.h" -#include "bfd.h" /* Required by objfiles.h. */ -#include "symfile.h" /* Required by objfiles.h. */ -#include "objfiles.h" /* For have_full_symbols and have_partial_symbols. */ -#include "top.h" -#include "completer.h" /* For skip_quoted(). */ -#include "block.h" - -#define parse_type builtin_type (parse_gdbarch) - -/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, - etc), as well as gratuitiously global symbol names, so we can have - multiple yacc generated parsers in gdb. Note that these are only - the variables produced by yacc. If other parser generators (bison, - byacc, etc) produce additional global names that conflict at link - time, then those parser generators need to be fixed instead of - adding those names to this list. */ - -#define yymaxdepth objc_maxdepth -#define yyparse objc_parse -#define yylex objc_lex -#define yyerror objc_error -#define yylval objc_lval -#define yychar objc_char -#define yydebug objc_debug -#define yypact objc_pact -#define yyr1 objc_r1 -#define yyr2 objc_r2 -#define yydef objc_def -#define yychk objc_chk -#define yypgo objc_pgo -#define yyact objc_act -#define yyexca objc_exca -#define yyerrflag objc_errflag -#define yynerrs objc_nerrs -#define yyps objc_ps -#define yypv objc_pv -#define yys objc_s -#define yy_yys objc_yys -#define yystate objc_state -#define yytmp objc_tmp -#define yyv objc_v -#define yy_yyv objc_yyv -#define yyval objc_val -#define yylloc objc_lloc -#define yyreds objc_reds /* With YYDEBUG defined */ -#define yytoks objc_toks /* With YYDEBUG defined */ -#define yyname objc_name /* With YYDEBUG defined */ -#define yyrule objc_rule /* With YYDEBUG defined */ -#define yylhs objc_yylhs -#define yylen objc_yylen -#define yydefred objc_yydefred -#define yydgoto objc_yydgoto -#define yysindex objc_yysindex -#define yyrindex objc_yyrindex -#define yygindex objc_yygindex -#define yytable objc_yytable -#define yycheck objc_yycheck - -#ifndef YYDEBUG -#define YYDEBUG 0 /* Default to no yydebug support. */ -#endif - -int yyparse (void); - -static int yylex (void); - -void yyerror (char *); - -%} - -/* Although the yacc "value" of an expression is not used, - since the result is stored in the structure being created, - other node types do have values. */ - -%union - { - LONGEST lval; - struct { - LONGEST val; - struct type *type; - } typed_val_int; - struct { - DOUBLEST dval; - struct type *type; - } typed_val_float; - struct symbol *sym; - struct type *tval; - struct stoken sval; - struct ttype tsym; - struct symtoken ssym; - int voidval; - struct block *bval; - enum exp_opcode opcode; - struct internalvar *ivar; - struct objc_class_str class; - - struct type **tvec; - int *ivec; - } - -%{ -/* YYSTYPE gets defined by %union. */ -static int parse_number (char *, int, int, YYSTYPE *); -%} - -%type exp exp1 type_exp start variable qualified_name lcurly -%type rcurly -%type type typebase -%type nonempty_typelist -/* %type block */ - -/* Fancy type parsing. */ -%type func_mod direct_abs_decl abs_decl -%type ptype -%type array_mod - -%token INT -%token FLOAT - -/* Both NAME and TYPENAME tokens represent symbols in the input, and - both convey their data as strings. But a TYPENAME is a string that - happens to be defined as a typedef or builtin type name (such as - int or char) and a NAME is any other symbol. Contexts where this - distinction is not important can use the nonterminal "name", which - matches either NAME or TYPENAME. */ - -%token STRING -%token NSSTRING /* ObjC Foundation "NSString" literal */ -%token SELECTOR /* ObjC "@selector" pseudo-operator */ -%token NAME /* BLOCKNAME defined below to give it higher precedence. */ -%token TYPENAME -%token CLASSNAME /* ObjC Class name */ -%type name -%type name_not_typename -%type typename - -/* A NAME_OR_INT is a symbol which is not known in the symbol table, - but which would parse as a valid number in the current input radix. - E.g. "c" when input_radix==16. Depending on the parse, it will be - turned into a name or into a number. */ - -%token NAME_OR_INT - -%token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON -%token TEMPLATE -%token ERROR - -/* Special type cases, put in to allow the parser to distinguish - different legal basetypes. */ -%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD - -%token VARIABLE - -%token ASSIGN_MODIFY - -%left ',' -%left ABOVE_COMMA -%right '=' ASSIGN_MODIFY -%right '?' -%left OROR -%left ANDAND -%left '|' -%left '^' -%left '&' -%left EQUAL NOTEQUAL -%left '<' '>' LEQ GEQ -%left LSH RSH -%left '@' -%left '+' '-' -%left '*' '/' '%' -%right UNARY INCREMENT DECREMENT -%right ARROW '.' '[' '(' -%token BLOCKNAME -%type block -%left COLONCOLON - - -%% - -start : exp1 - | type_exp - ; - -type_exp: type - { write_exp_elt_opcode(OP_TYPE); - write_exp_elt_type($1); - write_exp_elt_opcode(OP_TYPE);} - ; - -/* Expressions, including the comma operator. */ -exp1 : exp - | exp1 ',' exp - { write_exp_elt_opcode (BINOP_COMMA); } - ; - -/* Expressions, not including the comma operator. */ -exp : '*' exp %prec UNARY - { write_exp_elt_opcode (UNOP_IND); } - ; - -exp : '&' exp %prec UNARY - { write_exp_elt_opcode (UNOP_ADDR); } - ; - -exp : '-' exp %prec UNARY - { write_exp_elt_opcode (UNOP_NEG); } - ; - -exp : '!' exp %prec UNARY - { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } - ; - -exp : '~' exp %prec UNARY - { write_exp_elt_opcode (UNOP_COMPLEMENT); } - ; - -exp : INCREMENT exp %prec UNARY - { write_exp_elt_opcode (UNOP_PREINCREMENT); } - ; - -exp : DECREMENT exp %prec UNARY - { write_exp_elt_opcode (UNOP_PREDECREMENT); } - ; - -exp : exp INCREMENT %prec UNARY - { write_exp_elt_opcode (UNOP_POSTINCREMENT); } - ; - -exp : exp DECREMENT %prec UNARY - { write_exp_elt_opcode (UNOP_POSTDECREMENT); } - ; - -exp : SIZEOF exp %prec UNARY - { write_exp_elt_opcode (UNOP_SIZEOF); } - ; - -exp : exp ARROW name - { write_exp_elt_opcode (STRUCTOP_PTR); - write_exp_string ($3); - write_exp_elt_opcode (STRUCTOP_PTR); } - ; - -exp : exp ARROW qualified_name - { /* exp->type::name becomes exp->*(&type::name) */ - /* Note: this doesn't work if name is a - static member! FIXME */ - write_exp_elt_opcode (UNOP_ADDR); - write_exp_elt_opcode (STRUCTOP_MPTR); } - ; -exp : exp ARROW '*' exp - { write_exp_elt_opcode (STRUCTOP_MPTR); } - ; - -exp : exp '.' name - { write_exp_elt_opcode (STRUCTOP_STRUCT); - write_exp_string ($3); - write_exp_elt_opcode (STRUCTOP_STRUCT); } - ; - - -exp : exp '.' qualified_name - { /* exp.type::name becomes exp.*(&type::name) */ - /* Note: this doesn't work if name is a - static member! FIXME */ - write_exp_elt_opcode (UNOP_ADDR); - write_exp_elt_opcode (STRUCTOP_MEMBER); } - ; - -exp : exp '.' '*' exp - { write_exp_elt_opcode (STRUCTOP_MEMBER); } - ; - -exp : exp '[' exp1 ']' - { write_exp_elt_opcode (BINOP_SUBSCRIPT); } - ; -/* - * The rules below parse ObjC message calls of the form: - * '[' target selector {':' argument}* ']' - */ - -exp : '[' TYPENAME - { - CORE_ADDR class; - - class = lookup_objc_class (parse_gdbarch, - copy_name ($2.stoken)); - if (class == 0) - error (_("%s is not an ObjC Class"), - copy_name ($2.stoken)); - write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (parse_type->builtin_int); - write_exp_elt_longcst ((LONGEST) class); - write_exp_elt_opcode (OP_LONG); - start_msglist(); - } - msglist ']' - { write_exp_elt_opcode (OP_OBJC_MSGCALL); - end_msglist(); - write_exp_elt_opcode (OP_OBJC_MSGCALL); - } - ; - -exp : '[' CLASSNAME - { - write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (parse_type->builtin_int); - write_exp_elt_longcst ((LONGEST) $2.class); - write_exp_elt_opcode (OP_LONG); - start_msglist(); - } - msglist ']' - { write_exp_elt_opcode (OP_OBJC_MSGCALL); - end_msglist(); - write_exp_elt_opcode (OP_OBJC_MSGCALL); - } - ; - -exp : '[' exp - { start_msglist(); } - msglist ']' - { write_exp_elt_opcode (OP_OBJC_MSGCALL); - end_msglist(); - write_exp_elt_opcode (OP_OBJC_MSGCALL); - } - ; - -msglist : name - { add_msglist(&$1, 0); } - | msgarglist - ; - -msgarglist : msgarg - | msgarglist msgarg - ; - -msgarg : name ':' exp - { add_msglist(&$1, 1); } - | ':' exp /* Unnamed arg. */ - { add_msglist(0, 1); } - | ',' exp /* Variable number of args. */ - { add_msglist(0, 0); } - ; - -exp : exp '(' - /* This is to save the value of arglist_len - being accumulated by an outer function call. */ - { start_arglist (); } - arglist ')' %prec ARROW - { write_exp_elt_opcode (OP_FUNCALL); - write_exp_elt_longcst ((LONGEST) end_arglist ()); - write_exp_elt_opcode (OP_FUNCALL); } - ; - -lcurly : '{' - { start_arglist (); } - ; - -arglist : - ; - -arglist : exp - { arglist_len = 1; } - ; - -arglist : arglist ',' exp %prec ABOVE_COMMA - { arglist_len++; } - ; - -rcurly : '}' - { $$ = end_arglist () - 1; } - ; -exp : lcurly arglist rcurly %prec ARROW - { write_exp_elt_opcode (OP_ARRAY); - write_exp_elt_longcst ((LONGEST) 0); - write_exp_elt_longcst ((LONGEST) $3); - write_exp_elt_opcode (OP_ARRAY); } - ; - -exp : lcurly type rcurly exp %prec UNARY - { write_exp_elt_opcode (UNOP_MEMVAL); - write_exp_elt_type ($2); - write_exp_elt_opcode (UNOP_MEMVAL); } - ; - -exp : '(' type ')' exp %prec UNARY - { write_exp_elt_opcode (UNOP_CAST); - write_exp_elt_type ($2); - write_exp_elt_opcode (UNOP_CAST); } - ; - -exp : '(' exp1 ')' - { } - ; - -/* Binary operators in order of decreasing precedence. */ - -exp : exp '@' exp - { write_exp_elt_opcode (BINOP_REPEAT); } - ; - -exp : exp '*' exp - { write_exp_elt_opcode (BINOP_MUL); } - ; - -exp : exp '/' exp - { write_exp_elt_opcode (BINOP_DIV); } - ; - -exp : exp '%' exp - { write_exp_elt_opcode (BINOP_REM); } - ; - -exp : exp '+' exp - { write_exp_elt_opcode (BINOP_ADD); } - ; - -exp : exp '-' exp - { write_exp_elt_opcode (BINOP_SUB); } - ; - -exp : exp LSH exp - { write_exp_elt_opcode (BINOP_LSH); } - ; - -exp : exp RSH exp - { write_exp_elt_opcode (BINOP_RSH); } - ; - -exp : exp EQUAL exp - { write_exp_elt_opcode (BINOP_EQUAL); } - ; - -exp : exp NOTEQUAL exp - { write_exp_elt_opcode (BINOP_NOTEQUAL); } - ; - -exp : exp LEQ exp - { write_exp_elt_opcode (BINOP_LEQ); } - ; - -exp : exp GEQ exp - { write_exp_elt_opcode (BINOP_GEQ); } - ; - -exp : exp '<' exp - { write_exp_elt_opcode (BINOP_LESS); } - ; - -exp : exp '>' exp - { write_exp_elt_opcode (BINOP_GTR); } - ; - -exp : exp '&' exp - { write_exp_elt_opcode (BINOP_BITWISE_AND); } - ; - -exp : exp '^' exp - { write_exp_elt_opcode (BINOP_BITWISE_XOR); } - ; - -exp : exp '|' exp - { write_exp_elt_opcode (BINOP_BITWISE_IOR); } - ; - -exp : exp ANDAND exp - { write_exp_elt_opcode (BINOP_LOGICAL_AND); } - ; - -exp : exp OROR exp - { write_exp_elt_opcode (BINOP_LOGICAL_OR); } - ; - -exp : exp '?' exp ':' exp %prec '?' - { write_exp_elt_opcode (TERNOP_COND); } - ; - -exp : exp '=' exp - { write_exp_elt_opcode (BINOP_ASSIGN); } - ; - -exp : exp ASSIGN_MODIFY exp - { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); - write_exp_elt_opcode ($2); - write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); } - ; - -exp : INT - { write_exp_elt_opcode (OP_LONG); - write_exp_elt_type ($1.type); - write_exp_elt_longcst ((LONGEST)($1.val)); - write_exp_elt_opcode (OP_LONG); } - ; - -exp : NAME_OR_INT - { YYSTYPE val; - parse_number ($1.stoken.ptr, - $1.stoken.length, 0, &val); - write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (val.typed_val_int.type); - write_exp_elt_longcst ((LONGEST) - val.typed_val_int.val); - write_exp_elt_opcode (OP_LONG); - } - ; - - -exp : FLOAT - { write_exp_elt_opcode (OP_DOUBLE); - write_exp_elt_type ($1.type); - write_exp_elt_dblcst ($1.dval); - write_exp_elt_opcode (OP_DOUBLE); } - ; - -exp : variable - ; - -exp : VARIABLE - /* Already written by write_dollar_variable. */ - ; - -exp : SELECTOR - { - write_exp_elt_opcode (OP_OBJC_SELECTOR); - write_exp_string ($1); - write_exp_elt_opcode (OP_OBJC_SELECTOR); } - ; - -exp : SIZEOF '(' type ')' %prec UNARY - { write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (parse_type->builtin_int); - CHECK_TYPEDEF ($3); - write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); - write_exp_elt_opcode (OP_LONG); } - ; - -exp : STRING - { /* 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) - { - 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); - } - 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); } - ; - -exp : NSSTRING /* ObjC NextStep NSString constant - * of the form '@' '"' string '"'. - */ - { write_exp_elt_opcode (OP_OBJC_NSSTRING); - write_exp_string ($1); - write_exp_elt_opcode (OP_OBJC_NSSTRING); } - ; - -block : BLOCKNAME - { - if ($1.sym != 0) - $$ = SYMBOL_BLOCK_VALUE ($1.sym); - else - { - struct symtab *tem = - lookup_symtab (copy_name ($1.stoken)); - if (tem) - $$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), - STATIC_BLOCK); - else - error (_("No file or function \"%s\"."), - copy_name ($1.stoken)); - } - } - ; - -block : block COLONCOLON name - { struct symbol *tem - = lookup_symbol (copy_name ($3), $1, - VAR_DOMAIN, (int *) NULL); - if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) - error (_("No function \"%s\" in specified context."), - copy_name ($3)); - $$ = SYMBOL_BLOCK_VALUE (tem); } - ; - -variable: block COLONCOLON name - { struct symbol *sym; - sym = lookup_symbol (copy_name ($3), $1, - VAR_DOMAIN, (int *) NULL); - if (sym == 0) - error (_("No symbol \"%s\" in specified context."), - copy_name ($3)); - - write_exp_elt_opcode (OP_VAR_VALUE); - /* block_found is set by lookup_symbol. */ - write_exp_elt_block (block_found); - write_exp_elt_sym (sym); - write_exp_elt_opcode (OP_VAR_VALUE); } - ; - -qualified_name: typebase COLONCOLON name - { - struct type *type = $1; - if (TYPE_CODE (type) != TYPE_CODE_STRUCT - && TYPE_CODE (type) != TYPE_CODE_UNION) - error (_("`%s' is not defined as an aggregate type."), - TYPE_NAME (type)); - - write_exp_elt_opcode (OP_SCOPE); - write_exp_elt_type (type); - write_exp_string ($3); - write_exp_elt_opcode (OP_SCOPE); - } - | typebase COLONCOLON '~' name - { - struct type *type = $1; - struct stoken tmp_token; - if (TYPE_CODE (type) != TYPE_CODE_STRUCT - && TYPE_CODE (type) != TYPE_CODE_UNION) - error (_("`%s' is not defined as an aggregate type."), - TYPE_NAME (type)); - - if (strcmp (type_name_no_tag (type), $4.ptr) != 0) - error (_("invalid destructor `%s::~%s'"), - type_name_no_tag (type), $4.ptr); - - tmp_token.ptr = (char*) alloca ($4.length + 2); - tmp_token.length = $4.length + 1; - tmp_token.ptr[0] = '~'; - memcpy (tmp_token.ptr+1, $4.ptr, $4.length); - tmp_token.ptr[tmp_token.length] = 0; - write_exp_elt_opcode (OP_SCOPE); - write_exp_elt_type (type); - write_exp_string (tmp_token); - write_exp_elt_opcode (OP_SCOPE); - } - ; - -variable: 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); - if (sym) - { - write_exp_elt_opcode (OP_VAR_VALUE); - write_exp_elt_block (NULL); - write_exp_elt_sym (sym); - write_exp_elt_opcode (OP_VAR_VALUE); - break; - } - - msymbol = lookup_minimal_symbol (name, NULL, NULL); - if (msymbol != NULL) - write_exp_msymbol (msymbol); - else if (!have_full_symbols () - && !have_partial_symbols ()) - error (_("No symbol table is loaded. " - "Use the \"file\" command.")); - else - error (_("No symbol \"%s\" in current context."), - name); - } - ; - -variable: name_not_typename - { struct symbol *sym = $1.sym; - - if (sym) - { - if (symbol_read_needs_frame (sym)) - { - if (innermost_block == 0 || - contained_in (block_found, - innermost_block)) - innermost_block = block_found; - } - - write_exp_elt_opcode (OP_VAR_VALUE); - /* We want to use the selected frame, not - another more inner frame which happens to - be in the same block. */ - write_exp_elt_block (NULL); - write_exp_elt_sym (sym); - write_exp_elt_opcode (OP_VAR_VALUE); - } - else if ($1.is_a_field_of_this) - { - /* C++/ObjC: it hangs off of `this'/'self'. - Must not inadvertently convert from a - method call to data ref. */ - if (innermost_block == 0 || - contained_in (block_found, innermost_block)) - innermost_block = block_found; - write_exp_elt_opcode (OP_THIS); - write_exp_elt_opcode (OP_THIS); - write_exp_elt_opcode (STRUCTOP_PTR); - write_exp_string ($1.stoken); - write_exp_elt_opcode (STRUCTOP_PTR); - } - else - { - struct minimal_symbol *msymbol; - char *arg = copy_name ($1.stoken); - - msymbol = - lookup_minimal_symbol (arg, NULL, NULL); - if (msymbol != NULL) - write_exp_msymbol (msymbol); - else if (!have_full_symbols () && - !have_partial_symbols ()) - error (_("No symbol table is loaded. " - "Use the \"file\" command.")); - else - error (_("No symbol \"%s\" in current context."), - copy_name ($1.stoken)); - } - } - ; - - -ptype : typebase - /* "const" and "volatile" are curently ignored. A type - qualifier before the type is currently handled in the - typebase rule. The reason for recognizing these here - (shift/reduce conflicts) might be obsolete now that some - pointer to member rules have been deleted. */ - | typebase CONST_KEYWORD - | typebase VOLATILE_KEYWORD - | typebase abs_decl - { $$ = follow_types ($1); } - | typebase CONST_KEYWORD abs_decl - { $$ = follow_types ($1); } - | typebase VOLATILE_KEYWORD abs_decl - { $$ = follow_types ($1); } - ; - -abs_decl: '*' - { push_type (tp_pointer); $$ = 0; } - | '*' abs_decl - { push_type (tp_pointer); $$ = $2; } - | '&' - { push_type (tp_reference); $$ = 0; } - | '&' abs_decl - { push_type (tp_reference); $$ = $2; } - | direct_abs_decl - ; - -direct_abs_decl: '(' abs_decl ')' - { $$ = $2; } - | direct_abs_decl array_mod - { - push_type_int ($2); - push_type (tp_array); - } - | array_mod - { - push_type_int ($1); - push_type (tp_array); - $$ = 0; - } - - | direct_abs_decl func_mod - { push_type (tp_function); } - | func_mod - { push_type (tp_function); } - ; - -array_mod: '[' ']' - { $$ = -1; } - | '[' INT ']' - { $$ = $2.val; } - ; - -func_mod: '(' ')' - { $$ = 0; } - | '(' nonempty_typelist ')' - { free ($2); $$ = 0; } - ; - -/* We used to try to recognize more pointer to member types here, but - that didn't work (shift/reduce conflicts meant that these rules - never got executed). The problem is that - int (foo::bar::baz::bizzle) - is a function type but - int (foo::bar::baz::bizzle::*) - is a pointer to member type. Stroustrup loses again! */ - -type : ptype - ; - -typebase /* Implements (approximately): (type-qualifier)* type-specifier. */ - : TYPENAME - { $$ = $1.type; } - | CLASSNAME - { - if ($1.type == NULL) - error (_("No symbol \"%s\" in current context."), - copy_name($1.stoken)); - else - $$ = $1.type; - } - | INT_KEYWORD - { $$ = parse_type->builtin_int; } - | LONG - { $$ = parse_type->builtin_long; } - | SHORT - { $$ = parse_type->builtin_short; } - | LONG INT_KEYWORD - { $$ = parse_type->builtin_long; } - | UNSIGNED LONG INT_KEYWORD - { $$ = parse_type->builtin_unsigned_long; } - | LONG LONG - { $$ = parse_type->builtin_long_long; } - | LONG LONG INT_KEYWORD - { $$ = parse_type->builtin_long_long; } - | UNSIGNED LONG LONG - { $$ = parse_type->builtin_unsigned_long_long; } - | UNSIGNED LONG LONG INT_KEYWORD - { $$ = parse_type->builtin_unsigned_long_long; } - | SHORT INT_KEYWORD - { $$ = parse_type->builtin_short; } - | UNSIGNED SHORT INT_KEYWORD - { $$ = parse_type->builtin_unsigned_short; } - | DOUBLE_KEYWORD - { $$ = parse_type->builtin_double; } - | LONG DOUBLE_KEYWORD - { $$ = parse_type->builtin_long_double; } - | STRUCT name - { $$ = lookup_struct (copy_name ($2), - expression_context_block); } - | CLASS name - { $$ = lookup_struct (copy_name ($2), - expression_context_block); } - | UNION name - { $$ = lookup_union (copy_name ($2), - expression_context_block); } - | ENUM name - { $$ = lookup_enum (copy_name ($2), - expression_context_block); } - | UNSIGNED typename - { $$ = lookup_unsigned_typename (parse_language, - parse_gdbarch, - TYPE_NAME($2.type)); } - | UNSIGNED - { $$ = parse_type->builtin_unsigned_int; } - | SIGNED_KEYWORD typename - { $$ = lookup_signed_typename (parse_language, - parse_gdbarch, - TYPE_NAME($2.type)); } - | SIGNED_KEYWORD - { $$ = parse_type->builtin_int; } - | TEMPLATE name '<' type '>' - { $$ = lookup_template_type(copy_name($2), $4, - expression_context_block); - } - /* "const" and "volatile" are curently ignored. A type - qualifier after the type is handled in the ptype rule. I - think these could be too. */ - | CONST_KEYWORD typebase { $$ = $2; } - | VOLATILE_KEYWORD typebase { $$ = $2; } - ; - -typename: TYPENAME - | INT_KEYWORD - { - $$.stoken.ptr = "int"; - $$.stoken.length = 3; - $$.type = parse_type->builtin_int; - } - | LONG - { - $$.stoken.ptr = "long"; - $$.stoken.length = 4; - $$.type = parse_type->builtin_long; - } - | SHORT - { - $$.stoken.ptr = "short"; - $$.stoken.length = 5; - $$.type = parse_type->builtin_short; - } - ; - -nonempty_typelist - : type - { $$ = (struct type **) malloc (sizeof (struct type *) * 2); - $$[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); - $$[$$[0]] = $3; - } - ; - -name : NAME { $$ = $1.stoken; } - | BLOCKNAME { $$ = $1.stoken; } - | TYPENAME { $$ = $1.stoken; } - | CLASSNAME { $$ = $1.stoken; } - | NAME_OR_INT { $$ = $1.stoken; } - ; - -name_not_typename : NAME - | BLOCKNAME -/* These would be useful if name_not_typename was useful, but it is - just a fake for "variable", so these cause reduce/reduce conflicts - because the parser can't tell whether NAME_OR_INT is a - name_not_typename (=variable, =exp) or just an exp. If - name_not_typename was ever used in an lvalue context where only a - name could occur, this might be useful. */ -/* | NAME_OR_INT */ - ; - -%% - -/* Take care of parsing a number (anything that starts with a digit). - Set yylval and return the token type; update lexptr. LEN is the - number of characters in it. */ - -/*** Needs some error checking for the float case. ***/ - -static int -parse_number (p, len, parsed_float, putithere) - char *p; - int len; - int parsed_float; - YYSTYPE *putithere; -{ - /* FIXME: Shouldn't these be unsigned? We don't deal with negative - values here, and we do kind of silly things like cast to - unsigned. */ - LONGEST n = 0; - LONGEST prevn = 0; - unsigned LONGEST un; - - int i = 0; - int c; - int base = input_radix; - int unsigned_p = 0; - - /* Number of "L" suffixes encountered. */ - int long_p = 0; - - /* We have found a "L" or "U" suffix. */ - int found_suffix = 0; - - unsigned LONGEST high_bit; - struct type *signed_type; - struct type *unsigned_type; - - if (parsed_float) - { - if (! parse_c_float (parse_gdbarch, p, len, - &putithere->typed_val_float.dval, - &putithere->typed_val_float.type)) - return ERROR; - return FLOAT; - } - - /* Handle base-switching prefixes 0x, 0t, 0d, and 0. */ - if (p[0] == '0') - switch (p[1]) - { - case 'x': - case 'X': - if (len >= 3) - { - p += 2; - base = 16; - len -= 2; - } - break; - - case 't': - case 'T': - case 'd': - case 'D': - if (len >= 3) - { - p += 2; - base = 10; - len -= 2; - } - break; - - default: - base = 8; - break; - } - - while (len-- > 0) - { - c = *p++; - if (c >= 'A' && c <= 'Z') - c += 'a' - 'A'; - if (c != 'l' && c != 'u') - n *= base; - if (c >= '0' && c <= '9') - { - if (found_suffix) - return ERROR; - n += i = c - '0'; - } - else - { - if (base > 10 && c >= 'a' && c <= 'f') - { - if (found_suffix) - return ERROR; - n += i = c - 'a' + 10; - } - else if (c == 'l') - { - ++long_p; - found_suffix = 1; - } - else if (c == 'u') - { - unsigned_p = 1; - found_suffix = 1; - } - else - return ERROR; /* Char not a digit. */ - } - if (i >= base) - return ERROR; /* Invalid digit in this base. */ - - /* Portably test for overflow (only works for nonzero values, so - make a second check for zero). FIXME: Can't we just make n - and prevn unsigned and avoid this? */ - if (c != 'l' && c != 'u' && (prevn >= n) && n != 0) - unsigned_p = 1; /* Try something unsigned. */ - - /* Portably test for unsigned overflow. - FIXME: This check is wrong; for example it doesn't find - overflow on 0x123456789 when LONGEST is 32 bits. */ - if (c != 'l' && c != 'u' && n != 0) - { - if ((unsigned_p && (unsigned LONGEST) prevn >= (unsigned LONGEST) n)) - error (_("Numeric constant too large.")); - } - prevn = n; - } - - /* An integer constant is an int, a long, or a long long. An L - suffix forces it to be long; an LL suffix forces it to be long - long. If not forced to a larger size, it gets the first type of - the above that it fits in. To figure out whether it fits, we - shift it right and see whether anything remains. Note that we - can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or more in one - operation, because many compilers will warn about such a shift - (which always produces a zero result). Sometimes gdbarch_int_bit - or gdbarch_long_int will be that big, sometimes not. To deal with - the case where it is we just always shift the value more than - once, with fewer bits each time. */ - - un = (unsigned LONGEST)n >> 2; - if (long_p == 0 - && (un >> (gdbarch_int_bit (parse_gdbarch) - 2)) == 0) - { - high_bit - = ((unsigned LONGEST)1) << (gdbarch_int_bit (parse_gdbarch) - 1); - - /* A large decimal (not hex or octal) constant (between INT_MAX - and UINT_MAX) is a long or unsigned long, according to ANSI, - never an unsigned int, but this code treats it as unsigned - int. This probably should be fixed. GCC gives a warning on - such constants. */ - - unsigned_type = parse_type->builtin_unsigned_int; - signed_type = parse_type->builtin_int; - } - else if (long_p <= 1 - && (un >> (gdbarch_long_bit (parse_gdbarch) - 2)) == 0) - { - high_bit - = ((unsigned LONGEST)1) << (gdbarch_long_bit (parse_gdbarch) - 1); - unsigned_type = parse_type->builtin_unsigned_long; - signed_type = parse_type->builtin_long; - } - else - { - high_bit = (((unsigned LONGEST)1) - << (gdbarch_long_long_bit (parse_gdbarch) - 32 - 1) - << 16 - << 16); - if (high_bit == 0) - /* A long long does not fit in a LONGEST. */ - high_bit = - (unsigned LONGEST)1 << (sizeof (LONGEST) * HOST_CHAR_BIT - 1); - unsigned_type = parse_type->builtin_unsigned_long_long; - signed_type = parse_type->builtin_long_long; - } - - putithere->typed_val_int.val = n; - - /* If the high bit of the worked out type is set then this number - has to be unsigned. */ - - if (unsigned_p || (n & high_bit)) - { - putithere->typed_val_int.type = unsigned_type; - } - else - { - putithere->typed_val_int.type = signed_type; - } - - return INT; -} - -struct token -{ - char *operator; - int token; - enum exp_opcode opcode; -}; - -static const struct token tokentab3[] = - { - {">>=", ASSIGN_MODIFY, BINOP_RSH}, - {"<<=", ASSIGN_MODIFY, BINOP_LSH} - }; - -static const struct token tokentab2[] = - { - {"+=", ASSIGN_MODIFY, BINOP_ADD}, - {"-=", ASSIGN_MODIFY, BINOP_SUB}, - {"*=", ASSIGN_MODIFY, BINOP_MUL}, - {"/=", ASSIGN_MODIFY, BINOP_DIV}, - {"%=", ASSIGN_MODIFY, BINOP_REM}, - {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR}, - {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND}, - {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR}, - {"++", INCREMENT, BINOP_END}, - {"--", DECREMENT, BINOP_END}, - {"->", ARROW, BINOP_END}, - {"&&", ANDAND, BINOP_END}, - {"||", OROR, BINOP_END}, - {"::", COLONCOLON, BINOP_END}, - {"<<", LSH, BINOP_END}, - {">>", RSH, BINOP_END}, - {"==", EQUAL, BINOP_END}, - {"!=", NOTEQUAL, BINOP_END}, - {"<=", LEQ, BINOP_END}, - {">=", GEQ, BINOP_END} - }; - -/* Read one token, getting characters through lexptr. */ - -static int -yylex (void) -{ - int c, tokchr; - int namelen; - unsigned int i; - char *tokstart; - char *tokptr; - int tempbufindex; - static char *tempbuf; - static int tempbufsize; - - retry: - - tokstart = lexptr; - /* See if it is a special token of length 3. */ - for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) - if (strncmp (tokstart, tokentab3[i].operator, 3) == 0) - { - lexptr += 3; - yylval.opcode = tokentab3[i].opcode; - return tokentab3[i].token; - } - - /* See if it is a special token of length 2. */ - for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) - if (strncmp (tokstart, tokentab2[i].operator, 2) == 0) - { - lexptr += 2; - yylval.opcode = tokentab2[i].opcode; - return tokentab2[i].token; - } - - c = 0; - switch (tokchr = *tokstart) - { - case 0: - return 0; - - case ' ': - 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 (parse_gdbarch, &lexptr); - else if (c == '\'') - error (_("Empty character constant.")); - - 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++; - return '('; - - case ')': - if (paren_depth == 0) - return 0; - paren_depth--; - lexptr++; - return ')'; - - case ',': - if (comma_terminates && paren_depth == 0) - return 0; - lexptr++; - return ','; - - case '.': - /* Might be a floating point number. */ - if (lexptr[1] < '0' || lexptr[1] > '9') - goto symbol; /* Nope, must be a symbol. */ - /* FALL THRU into number case. */ - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - /* It's a number. */ - int got_dot = 0, got_e = 0, toktype = FLOAT; - /* Initialize toktype to anything other than ERROR. */ - char *p = tokstart; - int hex = input_radix > 10; - int local_radix = input_radix; - if (tokchr == '0' && (p[1] == 'x' || p[1] == 'X')) - { - p += 2; - hex = 1; - local_radix = 16; - } - else if (tokchr == '0' && (p[1]=='t' || p[1]=='T' - || p[1]=='d' || p[1]=='D')) - { - p += 2; - hex = 0; - local_radix = 10; - } - - for (;; ++p) - { - /* This test includes !hex because 'e' is a valid hex digit - and thus does not indicate a floating point number when - the radix is hex. */ - - if (!hex && (*p == 'e' || *p == 'E')) - if (got_e) - toktype = ERROR; /* Only one 'e' in a float. */ - else - got_e = 1; - /* This test does not include !hex, because a '.' always - indicates a decimal floating point number regardless of - the radix. */ - else if (*p == '.') - if (got_dot) - toktype = ERROR; /* Only one '.' in a float. */ - else - got_dot = 1; - else if (got_e && (p[-1] == 'e' || p[-1] == 'E') && - (*p == '-' || *p == '+')) - /* This is the sign of the exponent, not the end of the - number. */ - continue; - /* Always take decimal digits; parse_number handles radix - error. */ - else if (*p >= '0' && *p <= '9') - continue; - /* We will take letters only if hex is true, and only up - to what the input radix would permit. FSF was content - to rely on parse_number to validate; but it leaks. */ - else if (*p >= 'a' && *p <= 'z') - { - if (!hex || *p >= ('a' + local_radix - 10)) - toktype = ERROR; - } - else if (*p >= 'A' && *p <= 'Z') - { - if (!hex || *p >= ('A' + local_radix - 10)) - toktype = ERROR; - } - else break; - } - if (toktype != ERROR) - toktype = parse_number (tokstart, p - tokstart, - got_dot | got_e, &yylval); - if (toktype == ERROR) - { - char *err_copy = (char *) alloca (p - tokstart + 1); - - memcpy (err_copy, tokstart, p - tokstart); - err_copy[p - tokstart] = 0; - error (_("Invalid number \"%s\"."), err_copy); - } - lexptr = p; - return toktype; - } - - case '+': - case '-': - case '*': - case '/': - case '%': - case '|': - case '&': - case '^': - case '~': - case '!': -#if 0 - case '@': /* Moved out below. */ -#endif - case '<': - case '>': - case '[': - case ']': - case '?': - case ':': - case '=': - case '{': - case '}': - symbol: - lexptr++; - return tokchr; - - case '@': - if (strncmp(tokstart, "@selector", 9) == 0) - { - tokptr = strchr(tokstart, '('); - if (tokptr == NULL) - { - error (_("Missing '(' in @selector(...)")); - } - tempbufindex = 0; - tokptr++; /* Skip the '('. */ - do { - /* Grow the static temp buffer if necessary, including - allocating the first one on demand. */ - if (tempbufindex + 1 >= tempbufsize) - { - tempbuf = (char *) realloc (tempbuf, tempbufsize += 64); - } - tempbuf[tempbufindex++] = *tokptr++; - } while ((*tokptr != ')') && (*tokptr != '\0')); - if (*tokptr++ != ')') - { - error (_("Missing ')' in @selector(...)")); - } - tempbuf[tempbufindex] = '\0'; - yylval.sval.ptr = tempbuf; - yylval.sval.length = tempbufindex; - lexptr = tokptr; - return SELECTOR; - } - if (tokstart[1] != '"') - { - lexptr++; - return tokchr; - } - /* ObjC NextStep NSString constant: fall thru and parse like - STRING. */ - tokstart++; - - 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 { - /* 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) - { - case '\0': - case '"': - /* Do nothing, loop will terminate. */ - break; - case '\\': - tokptr++; - c = parse_escape (parse_gdbarch, &tokptr); - if (c == -1) - { - continue; - } - tempbuf[tempbufindex++] = c; - break; - default: - tempbuf[tempbufindex++] = *tokptr++; - break; - } - } 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 (tokchr == '@' ? NSSTRING : STRING); - } - - if (!(tokchr == '_' || tokchr == '$' || - (tokchr >= 'a' && tokchr <= 'z') || (tokchr >= 'A' && tokchr <= 'Z'))) - /* We must have come across a bad character (e.g. ';'). */ - 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 == '<');) - { - if (c == '<') - { - int i = namelen; - while (tokstart[++i] && tokstart[i] != '>'); - if (tokstart[i] == '>') - namelen = i; - } - c = tokstart[++namelen]; - } - - /* The token "if" terminates the expression and is NOT - removed from the input stream. */ - if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') - { - return 0; - } - - lexptr += namelen; - - tryname: - - /* Catch specific keywords. Should be done with a data structure. */ - switch (namelen) - { - case 8: - if (strncmp (tokstart, "unsigned", 8) == 0) - return UNSIGNED; - if (parse_language->la_language == language_cplus - && strncmp (tokstart, "template", 8) == 0) - return TEMPLATE; - if (strncmp (tokstart, "volatile", 8) == 0) - return VOLATILE_KEYWORD; - break; - case 6: - if (strncmp (tokstart, "struct", 6) == 0) - return STRUCT; - if (strncmp (tokstart, "signed", 6) == 0) - return SIGNED_KEYWORD; - if (strncmp (tokstart, "sizeof", 6) == 0) - return SIZEOF; - if (strncmp (tokstart, "double", 6) == 0) - return DOUBLE_KEYWORD; - break; - case 5: - if ((parse_language->la_language == language_cplus) - && strncmp (tokstart, "class", 5) == 0) - return CLASS; - if (strncmp (tokstart, "union", 5) == 0) - return UNION; - if (strncmp (tokstart, "short", 5) == 0) - return SHORT; - if (strncmp (tokstart, "const", 5) == 0) - return CONST_KEYWORD; - break; - case 4: - if (strncmp (tokstart, "enum", 4) == 0) - return ENUM; - if (strncmp (tokstart, "long", 4) == 0) - return LONG; - break; - case 3: - if (strncmp (tokstart, "int", 3) == 0) - return INT_KEYWORD; - break; - default: - break; - } - - yylval.sval.ptr = tokstart; - yylval.sval.length = namelen; - - if (*tokstart == '$') - { - write_dollar_variable (yylval.sval); - return VARIABLE; - } - - /* Use token-type BLOCKNAME for symbols that happen to be defined as - functions or symtabs. If this is not so, then ... - Use token-type TYPENAME for symbols that happen to be defined - currently as names of types; NAME for other symbols. - The caller is not constrained to care about the distinction. */ - { - char *tmp = copy_name (yylval.sval); - struct symbol *sym; - int is_a_field_of_this = 0, *need_this; - int hextype; - - if (parse_language->la_language == language_cplus || - parse_language->la_language == language_objc) - need_this = &is_a_field_of_this; - else - need_this = (int *) NULL; - - sym = lookup_symbol (tmp, expression_context_block, - VAR_DOMAIN, - need_this); - /* 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 symbols are read). */ - if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) || - lookup_symtab (tmp)) - { - yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; - return BLOCKNAME; - } - if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) - { -#if 1 - /* Despite the following flaw, we need to keep this code - enabled. Because we can get called from - check_stub_method, if we don't handle nested types then - it screws many operations in any program which uses - nested types. */ - /* In "A::x", if x is a member function of A and there - happens to be a type (nested or not, since the stabs - don't make that distinction) named x, then this code - incorrectly thinks we are dealing with nested types - rather than a member function. */ - - char *p; - char *namestart; - struct symbol *best_sym; - - /* Look ahead to detect nested types. This probably should - be done in the grammar, but trying seemed to introduce a - lot of shift/reduce and reduce/reduce conflicts. It's - possible that it could be done, though. Or perhaps a - non-grammar, but less ad hoc, approach would work well. */ - - /* Since we do not currently have any way of distinguishing - a nested type from a non-nested one (the stabs don't tell - us whether a type is nested), we just ignore the - containing type. */ - - p = lexptr; - best_sym = sym; - while (1) - { - /* Skip whitespace. */ - while (*p == ' ' || *p == '\t' || *p == '\n') - ++p; - if (*p == ':' && p[1] == ':') - { - /* Skip the `::'. */ - p += 2; - /* Skip whitespace. */ - while (*p == ' ' || *p == '\t' || *p == '\n') - ++p; - namestart = p; - while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9') - || (*p >= 'a' && *p <= 'z') - || (*p >= 'A' && *p <= 'Z')) - ++p; - if (p != namestart) - { - struct symbol *cur_sym; - /* As big as the whole rest of the expression, - which is at least big enough. */ - char *ncopy = alloca (strlen (tmp) + - strlen (namestart) + 3); - char *tmp1; - - tmp1 = ncopy; - memcpy (tmp1, tmp, strlen (tmp)); - tmp1 += strlen (tmp); - memcpy (tmp1, "::", 2); - tmp1 += 2; - memcpy (tmp1, namestart, p - namestart); - tmp1[p - namestart] = '\0'; - cur_sym = lookup_symbol (ncopy, - expression_context_block, - VAR_DOMAIN, (int *) NULL); - if (cur_sym) - { - if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF) - { - best_sym = cur_sym; - lexptr = p; - } - else - break; - } - else - break; - } - else - break; - } - else - break; - } - - yylval.tsym.type = SYMBOL_TYPE (best_sym); -#else /* not 0 */ - yylval.tsym.type = SYMBOL_TYPE (sym); -#endif /* not 0 */ - return TYPENAME; - } - yylval.tsym.type - = language_lookup_primitive_type_by_name (parse_language, - parse_gdbarch, tmp); - if (yylval.tsym.type != NULL) - return TYPENAME; - - /* See if it's an ObjC classname. */ - if (!sym) - { - CORE_ADDR Class = lookup_objc_class (parse_gdbarch, tmp); - if (Class) - { - yylval.class.class = Class; - if ((sym = lookup_struct_typedef (tmp, - expression_context_block, - 1))) - yylval.class.type = SYMBOL_TYPE (sym); - return CLASSNAME; - } - } - - /* Input names that aren't symbols but ARE valid hex numbers, - when the input radix permits them, can be names or numbers - depending on the parse. Note we support radixes > 16 here. */ - if (!sym && - ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) || - (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10))) - { - YYSTYPE newlval; /* Its value is ignored. */ - hextype = parse_number (tokstart, namelen, 0, &newlval); - if (hextype == INT) - { - yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; - return NAME_OR_INT; - } - } - - /* Any other kind of symbol. */ - yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; - return NAME; - } -} - -void -yyerror (msg) - char *msg; -{ - if (*lexptr == '\0') - error(_("A %s near end of expression."), (msg ? msg : "error")); - else - error (_("A %s in expression, near `%s'."), (msg ? msg : "error"), - lexptr); -} diff --git a/contrib/gdb-7/gdb/objc-lang.c b/contrib/gdb-7/gdb/objc-lang.c index 1c963096fa..734fc5d014 100644 --- a/contrib/gdb-7/gdb/objc-lang.c +++ b/contrib/gdb-7/gdb/objc-lang.c @@ -1,6 +1,6 @@ /* Objective-C language support routines for GDB, the GNU debugger. - Copyright (C) 2002-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. Contributed by Apple Computer, Inc. Written by Michael Snyder. @@ -44,6 +44,7 @@ #include "infcall.h" #include "valprint.h" #include "gdb_assert.h" +#include "cli/cli-utils.h" #include @@ -82,7 +83,7 @@ static const struct objfile_data *objc_objfile_data; suitably defined. */ struct symbol * -lookup_struct_typedef (char *name, struct block *block, int noerr) +lookup_struct_typedef (char *name, const struct block *block, int noerr) { struct symbol *sym; @@ -282,160 +283,6 @@ objc_demangle (const char *mangled, int options) return NULL; /* Not an objc mangled name. */ } -/* 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 -objc_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) -{ - c &= 0xFF; /* Avoid sign bit follies. */ - - if (PRINT_LITERAL_FORM (c)) - { - if (c == '\\' || c == quoter) - { - fputs_filtered ("\\", stream); - } - fprintf_filtered (stream, "%c", c); - } - else - { - switch (c) - { - case '\n': - fputs_filtered ("\\n", stream); - break; - case '\b': - fputs_filtered ("\\b", stream); - break; - case '\t': - fputs_filtered ("\\t", stream); - break; - case '\f': - fputs_filtered ("\\f", stream); - break; - case '\r': - fputs_filtered ("\\r", stream); - break; - case '\033': - fputs_filtered ("\\e", stream); - break; - case '\007': - fputs_filtered ("\\a", stream); - break; - default: - fprintf_filtered (stream, "\\%.3o", (unsigned int) c); - break; - } - } -} - -static void -objc_printchar (int c, struct type *type, struct ui_file *stream) -{ - fputs_filtered ("'", stream); - objc_emit_char (c, type, stream, '\''); - fputs_filtered ("'", stream); -} - -/* Print the character string STRING, printing at most LENGTH - characters. Printing stops early if the number hits print_max; - repeat counts are printed as appropriate. Print ellipses at the - end if we had to stop before printing LENGTH characters, or if - FORCE_ELLIPSES. */ - -static void -objc_printstr (struct ui_file *stream, struct type *type, - const gdb_byte *string, unsigned int length, - const char *encoding, 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; - - /* 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 && string[length-1] == '\0') - length--; - - if (length == 0) - { - fputs_filtered ("\"\"", stream); - return; - } - - for (i = 0; i < length && things_printed < options->print_max; ++i) - { - /* 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; - - QUIT; - - if (need_comma) - { - fputs_filtered (", ", stream); - need_comma = 0; - } - - rep1 = i + 1; - reps = 1; - while (rep1 < length && string[rep1] == string[i]) - { - ++rep1; - ++reps; - } - - if (reps > options->repeat_count_threshold) - { - if (in_quotes) - { - if (options->inspect_it) - fputs_filtered ("\\\", ", stream); - else - fputs_filtered ("\", ", stream); - in_quotes = 0; - } - objc_printchar (string[i], type, stream); - fprintf_filtered (stream, " ", reps); - i = rep1 - 1; - things_printed += options->repeat_count_threshold; - need_comma = 1; - } - else - { - if (!in_quotes) - { - if (options->inspect_it) - fputs_filtered ("\\\"", stream); - else - fputs_filtered ("\"", stream); - in_quotes = 1; - } - objc_emit_char (string[i], type, stream, '"'); - ++things_printed; - } - } - - /* Terminate the quotes if necessary. */ - if (in_quotes) - { - if (options->inspect_it) - fputs_filtered ("\\\"", stream); - else - fputs_filtered ("\"", stream); - } - - if (force_ellipses || i < length) - fputs_filtered ("...", stream); -} - /* Determine if we are currently in the Objective-C dispatch function. If so, get the address of the method function that the dispatcher would call and use that as the function to step into instead. Also @@ -509,21 +356,21 @@ const struct language_defn objc_language_defn = { "objective-c", /* Language name */ language_objc, range_check_off, - type_check_off, case_sensitive_on, array_row_major, macro_expansion_c, &exp_descriptor_standard, - objc_parse, - objc_error, + c_parse, + c_error, null_post_parser, - objc_printchar, /* Print a character constant */ - objc_printstr, /* Function to print string constant */ - objc_emit_char, + c_printchar, /* Print a character constant */ + c_printstr, /* Function to print string constant */ + c_emit_char, c_print_type, /* Print a type using appropriate syntax */ c_print_typedef, /* Print a typedef using appropriate syntax */ c_val_print, /* Print a value using appropriate syntax */ c_value_print, /* Print a top-level value */ + default_read_var_value, /* la_read_var_value */ objc_skip_trampoline, /* Language specific skip_trampoline */ "self", /* name_of_this */ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ @@ -540,7 +387,7 @@ const struct language_defn objc_language_defn = { default_print_array_index, default_pass_by_reference, default_get_string, - strcmp_iw_ordered, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, LANG_MAGIC }; @@ -636,14 +483,14 @@ end_msglist(void) } /* - * Function: specialcmp (char *a, char *b) + * Function: specialcmp (const char *a, const char *b) * * Special strcmp: treats ']' and ' ' as end-of-string. * Used for qsorting lists of objc methods (either by class or selector). */ static int -specialcmp (char *a, char *b) +specialcmp (const char *a, const char *b) { while (*a && *a != ' ' && *a != ']' && *b && *b != ' ' && *b != ']') { @@ -668,7 +515,7 @@ specialcmp (char *a, char *b) static int compare_selectors (const void *a, const void *b) { - char *aname, *bname; + const char *aname, *bname; aname = SYMBOL_PRINT_NAME (*(struct symbol **) a); bname = SYMBOL_PRINT_NAME (*(struct symbol **) b); @@ -697,7 +544,7 @@ selectors_info (char *regexp, int from_tty) { struct objfile *objfile; struct minimal_symbol *msymbol; - char *name; + const char *name; char *val; int matches = 0; int maxlen = 0; @@ -762,8 +609,8 @@ selectors_info (char *regexp, int from_tty) } if (regexp == NULL || re_exec(++name) != 0) { - char *mystart = name; - char *myend = (char *) strchr (mystart, ']'); + const char *mystart = name; + const char *myend = strchr (mystart, ']'); if (myend && (myend - mystart > maxlen)) maxlen = myend - mystart; /* Get longest selector. */ @@ -834,7 +681,7 @@ selectors_info (char *regexp, int from_tty) static int compare_classes (const void *a, const void *b) { - char *aname, *bname; + const char *aname, *bname; aname = SYMBOL_PRINT_NAME (*(struct symbol **) a); bname = SYMBOL_PRINT_NAME (*(struct symbol **) b); @@ -859,7 +706,7 @@ classes_info (char *regexp, int from_tty) { struct objfile *objfile; struct minimal_symbol *msymbol; - char *name; + const char *name; char *val; int matches = 0; int maxlen = 0; @@ -901,8 +748,8 @@ classes_info (char *regexp, int from_tty) if (regexp == NULL || re_exec(name+2) != 0) { /* Compute length of classname part. */ - char *mystart = name + 2; - char *myend = (char *) strchr(mystart, ' '); + const char *mystart = name + 2; + const char *myend = strchr (mystart, ' '); if (myend && (myend - mystart > maxlen)) maxlen = myend - mystart; @@ -966,15 +813,13 @@ parse_selector (char *method, char **selector) s1 = method; - while (isspace (*s1)) - s1++; + s1 = skip_spaces (s1); if (*s1 == '\'') { found_quote = 1; s1++; } - while (isspace (*s1)) - s1++; + s1 = skip_spaces (s1); nselector = s1; s2 = s1; @@ -993,14 +838,12 @@ parse_selector (char *method, char **selector) } *s1++ = '\0'; - while (isspace (*s2)) - s2++; + s2 = skip_spaces (s2); if (found_quote) { if (*s2 == '\'') s2++; - while (isspace (*s2)) - s2++; + s2 = skip_spaces (s2); } if (selector != NULL) @@ -1029,21 +872,18 @@ parse_method (char *method, char *type, char **class, s1 = method; - while (isspace (*s1)) - s1++; + s1 = skip_spaces (s1); if (*s1 == '\'') { found_quote = 1; s1++; } - while (isspace (*s1)) - s1++; + s1 = skip_spaces (s1); if ((s1[0] == '+') || (s1[0] == '-')) ntype = *s1++; - while (isspace (*s1)) - s1++; + s1 = skip_spaces (s1); if (*s1 != '[') return NULL; @@ -1054,14 +894,12 @@ parse_method (char *method, char *type, char **class, s1++; s2 = s1; - while (isspace (*s2)) - s2++; + s2 = skip_spaces (s2); if (*s2 == '(') { s2++; - while (isspace (*s2)) - s2++; + s2 = skip_spaces (s2); ncategory = s2; while (isalnum (*s2) || (*s2 == '_')) s2++; @@ -1089,15 +927,13 @@ parse_method (char *method, char *type, char **class, *s1++ = '\0'; s2++; - while (isspace (*s2)) - s2++; + s2 = skip_spaces (s2); if (found_quote) { if (*s2 != '\'') return NULL; s2++; - while (isspace (*s2)) - s2++; + s2 = skip_spaces (s2); } if (type != NULL) @@ -1119,7 +955,7 @@ find_methods (char type, const char *class, const char *category, { struct objfile *objfile = NULL; - char *symname = NULL; + const char *symname = NULL; char ntype = '\0'; char *nclass = NULL; @@ -1150,8 +986,6 @@ find_methods (char type, const char *class, const char *category, ALL_OBJFILE_MSYMBOLS (objfile, msymbol) { - struct gdbarch *gdbarch = get_objfile_arch (objfile); - QUIT; /* Check the symbol name first as this can be done entirely without @@ -1766,6 +1600,9 @@ resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc) return 0; } +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_objc_lang; + void _initialize_objc_lang (void) { diff --git a/contrib/gdb-7/gdb/objc-lang.h b/contrib/gdb-7/gdb/objc-lang.h index 593ef02222..23fac1b720 100644 --- a/contrib/gdb-7/gdb/objc-lang.h +++ b/contrib/gdb-7/gdb/objc-lang.h @@ -1,6 +1,6 @@ /* Objective-C language support definitions for GDB, the GNU debugger. - Copyright (C) 1992, 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. Contributed by Apple Computer, Inc. @@ -27,10 +27,6 @@ struct stoken; struct value; struct block; -extern int objc_parse (void); /* Defined in c-exp.y */ - -extern void objc_error (char *); /* Defined in c-exp.y */ - extern CORE_ADDR lookup_objc_class (struct gdbarch *gdbarch, char *classname); extern CORE_ADDR lookup_child_selector (struct gdbarch *gdbarch, @@ -50,7 +46,7 @@ extern void start_msglist (void); extern void add_msglist (struct stoken *str, int addcolon); extern int end_msglist (void); -struct symbol *lookup_struct_typedef (char *name, struct block *block, +struct symbol *lookup_struct_typedef (char *name, const struct block *block, int noerr); #endif diff --git a/contrib/gdb-7/gdb/objfiles.c b/contrib/gdb-7/gdb/objfiles.c index afe4fb4322..3017fdfc7a 100644 --- a/contrib/gdb-7/gdb/objfiles.c +++ b/contrib/gdb-7/gdb/objfiles.c @@ -1,6 +1,6 @@ /* GDB routines for manipulating objfiles. - Copyright (C) 1992-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. Contributed by Cygnus Support, using pieces from other GDB modules. @@ -30,7 +30,6 @@ #include "gdb-stabs.h" #include "target.h" #include "bcache.h" -#include "mdebugread.h" #include "expression.h" #include "parser-defs.h" @@ -53,11 +52,13 @@ #include "complaints.h" #include "psymtab.h" #include "solist.h" +#include "gdb_bfd.h" +#include "btrace.h" -/* Prototypes for local functions */ +/* Keep a registry of per-objfile data-pointers required by other GDB + modules. */ -static void objfile_alloc_data (struct objfile *objfile); -static void objfile_free_data (struct objfile *objfile); +DEFINE_REGISTRY (objfile, REGISTRY_ACCESS_FIELD) /* Externally visible variables that are owned by this module. See declarations in objfile.h for more info. */ @@ -105,12 +106,75 @@ get_objfile_pspace_data (struct program_space *pspace) return info; } -/* Records whether any objfiles appeared or disappeared since we last updated - address to obj section map. */ + + +/* Per-BFD data key. */ + +static const struct bfd_data *objfiles_bfd_data; + +/* Create the per-BFD storage object for OBJFILE. If ABFD is not + NULL, and it already has a per-BFD storage object, use that. + Otherwise, allocate a new per-BFD storage object. If ABFD is not + NULL, the object is allocated on the BFD; otherwise it is allocated + on OBJFILE's obstack. Note that it is not safe to call this + multiple times for a given OBJFILE -- it can only be called when + allocating or re-initializing OBJFILE. */ + +static struct objfile_per_bfd_storage * +get_objfile_bfd_data (struct objfile *objfile, struct bfd *abfd) +{ + struct objfile_per_bfd_storage *storage = NULL; + + if (abfd != NULL) + storage = bfd_data (abfd, objfiles_bfd_data); + + if (storage == NULL) + { + if (abfd != NULL) + { + storage = bfd_zalloc (abfd, sizeof (struct objfile_per_bfd_storage)); + set_bfd_data (abfd, objfiles_bfd_data, storage); + } + else + storage = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct objfile_per_bfd_storage); + + obstack_init (&storage->storage_obstack); + storage->filename_cache = bcache_xmalloc (NULL, NULL); + storage->macro_cache = bcache_xmalloc (NULL, NULL); + } + + return storage; +} + +/* Free STORAGE. */ + +static void +free_objfile_per_bfd_storage (struct objfile_per_bfd_storage *storage) +{ + bcache_xfree (storage->filename_cache); + bcache_xfree (storage->macro_cache); + obstack_free (&storage->storage_obstack, 0); +} + +/* A wrapper for free_objfile_per_bfd_storage that can be passed as a + cleanup function to the BFD registry. */ + +static void +objfile_bfd_data_free (struct bfd *unused, void *d) +{ + free_objfile_per_bfd_storage (d); +} + +/* See objfiles.h. */ + +void +set_objfile_per_bfd (struct objfile *objfile) +{ + objfile->per_bfd = get_objfile_bfd_data (objfile, objfile->obfd); +} -/* Locate all mappable sections of a BFD file. - objfile_p_char is a char * to get it through - bfd_map_over_sections; we cast it back to its proper type. */ + /* Called via bfd_map_over_sections to build up the section table that the objfile references. The objfile contains pointers to the start @@ -119,19 +183,18 @@ get_objfile_pspace_data (struct program_space *pspace) static void add_to_objfile_sections (struct bfd *abfd, struct bfd_section *asect, - void *objfile_p_char) + void *objfilep) { - struct objfile *objfile = (struct objfile *) objfile_p_char; + struct objfile *objfile = (struct objfile *) objfilep; struct obj_section section; flagword aflag; aflag = bfd_get_section_flags (abfd, asect); - if (!(aflag & SEC_ALLOC)) return; - - if (0 == bfd_section_size (abfd, asect)) + if (bfd_section_size (abfd, asect) == 0) return; + section.objfile = objfile; section.the_bfd_section = asect; section.ovly_mapped = 0; @@ -142,11 +205,9 @@ add_to_objfile_sections (struct bfd *abfd, struct bfd_section *asect, } /* Builds a section table for OBJFILE. - Returns 0 if OK, 1 on error (in which case bfd_error contains the - error). Note that while we are building the table, which goes into the - psymbol obstack, we hijack the sections_end pointer to instead hold + objfile obstack, we hijack the sections_end pointer to instead hold a count of the number of sections. When bfd_map_over_sections returns, this count is used to compute the pointer to the end of the sections table, which then overwrites the count. @@ -154,10 +215,10 @@ add_to_objfile_sections (struct bfd *abfd, struct bfd_section *asect, Also note that the OFFSET and OVLY_MAPPED in each table entry are initialized to zero. - Also note that if anything else writes to the psymbol obstack while + Also note that if anything else writes to the objfile obstack while we are building the table, we're pretty much hosed. */ -int +void build_objfile_section_table (struct objfile *objfile) { objfile->sections_end = 0; @@ -165,7 +226,6 @@ build_objfile_section_table (struct objfile *objfile) add_to_objfile_sections, (void *) objfile); objfile->sections = obstack_finish (&objfile->objfile_obstack); objfile->sections_end = objfile->sections + (size_t) objfile->sections_end; - return (0); } /* Given a pointer to an initialized bfd (ABFD) and some flag bits @@ -193,8 +253,6 @@ allocate_objfile (bfd *abfd, int flags) objfile = (struct objfile *) xzalloc (sizeof (struct objfile)); objfile->psymbol_cache = psymbol_bcache_init (); - objfile->macro_cache = bcache_xmalloc (NULL, NULL); - objfile->filename_cache = bcache_xmalloc (NULL, NULL); /* We could use obstack_specify_allocation here instead, but gdb_obstack.h specifies the alloc/dealloc functions. */ obstack_init (&objfile->objfile_obstack); @@ -206,28 +264,25 @@ allocate_objfile (bfd *abfd, int flags) that any data that is reference is saved in the per-objfile data region. */ - objfile->obfd = gdb_bfd_ref (abfd); + objfile->obfd = abfd; + gdb_bfd_ref (abfd); if (abfd != NULL) { /* Look up the gdbarch associated with the BFD. */ objfile->gdbarch = gdbarch_from_bfd (abfd); - objfile->name = xstrdup (bfd_get_filename (abfd)); + objfile->name = bfd_get_filename (abfd); objfile->mtime = bfd_get_mtime (abfd); /* Build section table. */ - - if (build_objfile_section_table (objfile)) - { - error (_("Can't find the file sections in `%s': %s"), - objfile->name, bfd_errmsg (bfd_get_error ())); - } + build_objfile_section_table (objfile); } else { - objfile->name = xstrdup ("<>"); + objfile->name = "<>"; } + objfile->per_bfd = get_objfile_bfd_data (objfile, abfd); objfile->pspace = current_program_space; /* Initialize the section indexes for this objfile, so that we can @@ -269,63 +324,17 @@ get_objfile_arch (struct objfile *objfile) return objfile->gdbarch; } -/* Initialize entry point information for this objfile. */ - -void -init_entry_point_info (struct objfile *objfile) -{ - /* Save startup file's range of PC addresses to help blockframe.c - decide where the bottom of the stack is. */ - - if (bfd_get_file_flags (objfile->obfd) & EXEC_P) - { - /* Executable file -- record its entry point so we'll recognize - the startup file because it contains the entry point. */ - objfile->ei.entry_point = bfd_get_start_address (objfile->obfd); - objfile->ei.entry_point_p = 1; - } - else if (bfd_get_file_flags (objfile->obfd) & DYNAMIC - && bfd_get_start_address (objfile->obfd) != 0) - { - /* Some shared libraries may have entry points set and be - runnable. There's no clear way to indicate this, so just check - for values other than zero. */ - objfile->ei.entry_point = bfd_get_start_address (objfile->obfd); - objfile->ei.entry_point_p = 1; - } - else - { - /* Examination of non-executable.o files. Short-circuit this stuff. */ - objfile->ei.entry_point_p = 0; - } -} - /* If there is a valid and known entry point, function fills *ENTRY_P with it and returns non-zero; otherwise it returns zero. */ int entry_point_address_query (CORE_ADDR *entry_p) { - struct gdbarch *gdbarch; - CORE_ADDR entry_point; - if (symfile_objfile == NULL || !symfile_objfile->ei.entry_point_p) return 0; - gdbarch = get_objfile_arch (symfile_objfile); - - entry_point = symfile_objfile->ei.entry_point; + *entry_p = symfile_objfile->ei.entry_point; - /* Make certain that the address points at real code, and not a - function descriptor. */ - entry_point = gdbarch_convert_from_func_ptr_addr (gdbarch, entry_point, - ¤t_target); - - /* Remove any ISA markers, so that this matches entries in the - symbol table. */ - entry_point = gdbarch_addr_bits_remove (gdbarch, entry_point); - - *entry_p = entry_point; return 1; } @@ -342,29 +351,6 @@ entry_point_address (void) return retval; } -/* Create the terminating entry of OBJFILE's minimal symbol table. - If OBJFILE->msymbols is zero, allocate a single entry from - OBJFILE->objfile_obstack; otherwise, just initialize - OBJFILE->msymbols[OBJFILE->minimal_symbol_count]. */ -void -terminate_minimal_symbol_table (struct objfile *objfile) -{ - if (! objfile->msymbols) - objfile->msymbols = ((struct minimal_symbol *) - obstack_alloc (&objfile->objfile_obstack, - sizeof (objfile->msymbols[0]))); - - { - struct minimal_symbol *m - = &objfile->msymbols[objfile->minimal_symbol_count]; - - memset (m, 0, sizeof (*m)); - /* Don't rely on these enumeration values being 0's. */ - MSYMBOL_TYPE (m) = mst_unknown; - SYMBOL_SET_LANGUAGE (m, language_unknown); - } -} - /* Iterator on PARENT and every separate debug objfile of PARENT. The usage pattern is: for (objfile = parent; @@ -491,6 +477,9 @@ add_separate_debug_objfile (struct objfile *objfile, struct objfile *parent) /* Must not be already in a list. */ gdb_assert (objfile->separate_debug_objfile_backlink == NULL); gdb_assert (objfile->separate_debug_objfile_link == NULL); + gdb_assert (objfile->separate_debug_objfile == NULL); + gdb_assert (parent->separate_debug_objfile_backlink == NULL); + gdb_assert (parent->separate_debug_objfile_link == NULL); objfile->separate_debug_objfile_backlink = parent; objfile->separate_debug_objfile_link = parent->separate_debug_objfile; @@ -578,6 +567,9 @@ free_objfile (struct objfile *objfile) the symbol file data. */ forget_cached_source_info_for_objfile (objfile); + breakpoint_free_objfile (objfile); + btrace_free_objfile (objfile); + /* First do any symbol file specific actions required when we are finished with a particular symbol file. Note that if the objfile is using reusable symbol information (via mmalloc) then each of @@ -594,7 +586,10 @@ free_objfile (struct objfile *objfile) still may reference objfile->obfd. */ objfile_free_data (objfile); - gdb_bfd_unref (objfile->obfd); + if (objfile->obfd) + gdb_bfd_unref (objfile->obfd); + else + free_objfile_per_bfd_storage (objfile->per_bfd); /* Remove it from the chain of all objfiles. */ @@ -635,15 +630,12 @@ free_objfile (struct objfile *objfile) /* The last thing we do is free the objfile struct itself. */ - xfree (objfile->name); if (objfile->global_psymbols.list) xfree (objfile->global_psymbols.list); if (objfile->static_psymbols.list) xfree (objfile->static_psymbols.list); /* Free the obstacks for non-reusable objfiles. */ psymbol_bcache_free (objfile->psymbol_cache); - bcache_xfree (objfile->macro_cache); - bcache_xfree (objfile->filename_cache); if (objfile->demangled_names_hash) htab_delete (objfile->demangled_names_hash); obstack_free (&objfile->objfile_obstack, 0); @@ -769,7 +761,9 @@ objfile_relocate1 (struct objfile *objfile, BLOCK_START (b) += ANOFFSET (delta, s->block_line_section); BLOCK_END (b) += ANOFFSET (delta, s->block_line_section); - ALL_BLOCK_SYMBOLS (b, iter, sym) + /* We only want to iterate over the local symbols, not any + symbols in included symtabs. */ + ALL_DICT_SYMBOLS (BLOCK_DICT (b), iter, sym) { relocate_one_symbol (sym, objfile, delta); } @@ -834,6 +828,11 @@ objfile_relocate1 (struct objfile *objfile, obj_section_addr (s)); } + /* Relocating probes. */ + if (objfile->sf && objfile->sf->sym_probe_fns) + objfile->sf->sym_probe_fns->sym_relocate_probe (objfile, + new_offsets, delta); + /* Data changed. */ return 1; } @@ -889,6 +888,45 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets) if (changed) breakpoint_re_set (); } + +/* Rebase (add to the offsets) OBJFILE by SLIDE. SEPARATE_DEBUG_OBJFILE is + not touched here. + Return non-zero iff any change happened. */ + +static int +objfile_rebase1 (struct objfile *objfile, CORE_ADDR slide) +{ + struct section_offsets *new_offsets = + ((struct section_offsets *) + alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections))); + int i; + + for (i = 0; i < objfile->num_sections; ++i) + new_offsets->offsets[i] = slide; + + return objfile_relocate1 (objfile, new_offsets); +} + +/* Rebase (add to the offsets) OBJFILE by SLIDE. Process also OBJFILE's + SEPARATE_DEBUG_OBJFILEs. */ + +void +objfile_rebase (struct objfile *objfile, CORE_ADDR slide) +{ + struct objfile *debug_objfile; + int changed = 0; + + changed |= objfile_rebase1 (objfile, slide); + + for (debug_objfile = objfile->separate_debug_objfile; + debug_objfile; + debug_objfile = objfile_separate_debug_iterate (objfile, debug_objfile)) + changed |= objfile_rebase1 (debug_objfile, slide); + + /* Relocate breakpoints as necessary, after things are relocated. */ + if (changed) + breakpoint_re_set (); +} /* Return non-zero if OBJFILE has partial symbols. */ @@ -1115,7 +1153,7 @@ insert_section_p (const struct bfd *abfd, { const bfd_vma lma = bfd_section_lma (abfd, section); - if (lma != 0 && lma != bfd_section_vma (abfd, section) + if (overlay_debugging && lma != 0 && lma != bfd_section_vma (abfd, section) && (bfd_get_file_flags (abfd) & BFD_IN_MEMORY) == 0) /* This is an overlay section. IN_MEMORY check is needed to avoid discarding sections from the "system supplied DSO" (aka vdso) @@ -1203,9 +1241,6 @@ filter_overlapping_sections (struct obj_section **map, int map_size) struct objfile *const objf1 = sect1->objfile; struct objfile *const objf2 = sect2->objfile; - const struct bfd *const abfd1 = objf1->obfd; - const struct bfd *const abfd2 = objf2->obfd; - const struct bfd_section *const bfds1 = sect1->the_bfd_section; const struct bfd_section *const bfds2 = sect2->the_bfd_section; @@ -1369,115 +1404,6 @@ in_plt_section (CORE_ADDR pc, char *name) } -/* Keep a registry of per-objfile data-pointers required by other GDB - modules. */ - -struct objfile_data -{ - unsigned index; - void (*save) (struct objfile *, void *); - void (*free) (struct objfile *, void *); -}; - -struct objfile_data_registration -{ - struct objfile_data *data; - struct objfile_data_registration *next; -}; - -struct objfile_data_registry -{ - struct objfile_data_registration *registrations; - unsigned num_registrations; -}; - -static struct objfile_data_registry objfile_data_registry = { NULL, 0 }; - -const struct objfile_data * -register_objfile_data_with_cleanup (void (*save) (struct objfile *, void *), - void (*free) (struct objfile *, void *)) -{ - struct objfile_data_registration **curr; - - /* Append new registration. */ - for (curr = &objfile_data_registry.registrations; - *curr != NULL; curr = &(*curr)->next); - - *curr = XMALLOC (struct objfile_data_registration); - (*curr)->next = NULL; - (*curr)->data = XMALLOC (struct objfile_data); - (*curr)->data->index = objfile_data_registry.num_registrations++; - (*curr)->data->save = save; - (*curr)->data->free = free; - - return (*curr)->data; -} - -const struct objfile_data * -register_objfile_data (void) -{ - return register_objfile_data_with_cleanup (NULL, NULL); -} - -static void -objfile_alloc_data (struct objfile *objfile) -{ - gdb_assert (objfile->data == NULL); - objfile->num_data = objfile_data_registry.num_registrations; - objfile->data = XCALLOC (objfile->num_data, void *); -} - -static void -objfile_free_data (struct objfile *objfile) -{ - gdb_assert (objfile->data != NULL); - clear_objfile_data (objfile); - xfree (objfile->data); - objfile->data = NULL; -} - -void -clear_objfile_data (struct objfile *objfile) -{ - struct objfile_data_registration *registration; - int i; - - gdb_assert (objfile->data != NULL); - - /* Process all the save handlers. */ - - for (registration = objfile_data_registry.registrations, i = 0; - i < objfile->num_data; - registration = registration->next, i++) - if (objfile->data[i] != NULL && registration->data->save != NULL) - registration->data->save (objfile, objfile->data[i]); - - /* Now process all the free handlers. */ - - for (registration = objfile_data_registry.registrations, i = 0; - i < objfile->num_data; - registration = registration->next, i++) - if (objfile->data[i] != NULL && registration->data->free != NULL) - registration->data->free (objfile, objfile->data[i]); - - memset (objfile->data, 0, objfile->num_data * sizeof (void *)); -} - -void -set_objfile_data (struct objfile *objfile, const struct objfile_data *data, - void *value) -{ - gdb_assert (data->index < objfile->num_data); - objfile->data[data->index] = value; -} - -void * -objfile_data (struct objfile *objfile, const struct objfile_data *data) -{ - gdb_assert (data->index < objfile->num_data); - return objfile->data[data->index]; -} - /* Set objfiles_changed_p so section map will be rebuilt next time it is used. Called by reread_symbols. */ @@ -1488,73 +1414,29 @@ objfiles_changed (void) get_objfile_pspace_data (current_program_space)->objfiles_changed_p = 1; } -/* Close ABFD, and warn if that fails. */ +/* The default implementation for the "iterate_over_objfiles_in_search_order" + gdbarch method. It is equivalent to use the ALL_OBJFILES macro, + searching the objfiles in the order they are stored internally, + ignoring CURRENT_OBJFILE. -int -gdb_bfd_close_or_warn (struct bfd *abfd) -{ - int ret; - char *name = bfd_get_filename (abfd); - - ret = bfd_close (abfd); + On most platorms, it should be close enough to doing the best + we can without some knowledge specific to the architecture. */ - if (!ret) - warning (_("cannot close \"%s\": %s"), - name, bfd_errmsg (bfd_get_error ())); - - return ret; -} - -/* Add reference to ABFD. Returns ABFD. */ -struct bfd * -gdb_bfd_ref (struct bfd *abfd) +void +default_iterate_over_objfiles_in_search_order + (struct gdbarch *gdbarch, + iterate_over_objfiles_in_search_order_cb_ftype *cb, + void *cb_data, struct objfile *current_objfile) { - int *p_refcount; - - if (abfd == NULL) - return NULL; - - p_refcount = bfd_usrdata (abfd); + int stop = 0; + struct objfile *objfile; - if (p_refcount != NULL) + ALL_OBJFILES (objfile) { - *p_refcount += 1; - return abfd; + stop = cb (objfile, cb_data); + if (stop) + return; } - - p_refcount = xmalloc (sizeof (*p_refcount)); - *p_refcount = 1; - bfd_usrdata (abfd) = p_refcount; - - return abfd; -} - -/* Unreference and possibly close ABFD. */ -void -gdb_bfd_unref (struct bfd *abfd) -{ - int *p_refcount; - char *name; - - if (abfd == NULL) - return; - - p_refcount = bfd_usrdata (abfd); - - /* Valid range for p_refcount: a pointer to int counter, which has a - value of 1 (single owner) or 2 (shared). */ - gdb_assert (*p_refcount == 1 || *p_refcount == 2); - - *p_refcount -= 1; - if (*p_refcount > 0) - return; - - xfree (p_refcount); - bfd_usrdata (abfd) = NULL; /* Paranoia. */ - - name = bfd_get_filename (abfd); - gdb_bfd_close_or_warn (abfd); - xfree (name); } /* Provide a prototype to silence -Wmissing-prototypes. */ @@ -1564,5 +1446,9 @@ void _initialize_objfiles (void) { objfiles_pspace_data - = register_program_space_data_with_cleanup (objfiles_pspace_data_cleanup); + = register_program_space_data_with_cleanup (NULL, + objfiles_pspace_data_cleanup); + + objfiles_bfd_data = register_bfd_data_with_cleanup (NULL, + objfile_bfd_data_free); } diff --git a/contrib/gdb-7/gdb/objfiles.h b/contrib/gdb-7/gdb/objfiles.h index aba1791498..cbfbed222c 100644 --- a/contrib/gdb-7/gdb/objfiles.h +++ b/contrib/gdb-7/gdb/objfiles.h @@ -1,6 +1,6 @@ /* Definitions for symbol file management in GDB. - Copyright (C) 1992-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -23,6 +23,7 @@ #include "gdb_obstack.h" /* For obstack internals. */ #include "symfile.h" /* For struct psymbol_allocation_list. */ #include "progspace.h" +#include "registry.h" struct bcache; struct htab; @@ -159,6 +160,25 @@ extern void print_symbol_bcache_statistics (void); /* Number of entries in the minimal symbol hash table. */ #define MINIMAL_SYMBOL_HASH_SIZE 2039 +/* Some objfile data is hung off the BFD. This enables sharing of the + data across all objfiles using the BFD. The data is stored in an + instance of this structure, and associated with the BFD using the + registry system. */ + +struct objfile_per_bfd_storage +{ + /* The storage has an obstack of its own. */ + + struct obstack storage_obstack; + + /* Byte cache for file names. */ + + struct bcache *filename_cache; + + /* Byte cache for macros. */ + struct bcache *macro_cache; +}; + /* Master structure for keeping track of each file from which gdb reads symbols. There are several ways these get allocated: 1. The main symbol file, symfile_objfile, set by the symbol-file command, @@ -177,8 +197,9 @@ struct objfile struct objfile *next; - /* The object file's name, tilde-expanded and absolute. Malloc'd; free it - if you free this struct. This pointer is never NULL. */ + /* The object file's name, tilde-expanded and absolute. This + pointer is never NULL. This does not have to be freed; it is + guaranteed to have a lifetime at least as long as the objfile. */ char *name; @@ -221,6 +242,11 @@ struct objfile bfd *obfd; + /* The per-BFD data. Note that this is treated specially if OBFD + is NULL. */ + + struct objfile_per_bfd_storage *per_bfd; + /* The gdbarch associated with the BFD. Note that this gdbarch is determined solely from BFD information, without looking at target information. The gdbarch determined from a running target may @@ -247,8 +273,6 @@ struct objfile will not change. */ struct psymbol_bcache *psymbol_cache; /* Byte cache for partial syms. */ - struct bcache *macro_cache; /* Byte cache for macros. */ - struct bcache *filename_cache; /* Byte cache for file names. */ /* Hash table for mapping symbol names to demangled names. Each entry in the hash table is actually two consecutive strings, @@ -298,42 +322,18 @@ struct objfile struct entry_info ei; - /* Information about stabs. Will be filled in with a dbx_symfile_info - struct by those readers that need it. */ - /* NOTE: cagney/2004-10-23: This has been replaced by per-objfile - data points implemented using "data" and "num_data" below. For - an example of how to use this replacement, see "objfile_data" - in "mips-tdep.c". */ - - struct dbx_symfile_info *deprecated_sym_stab_info; - - /* Hook for information for use by the symbol reader (currently used - for information shared by sym_init and sym_read). It is - typically a pointer to malloc'd memory. The symbol reader's finish - function is responsible for freeing the memory thusly allocated. */ - /* NOTE: cagney/2004-10-23: This has been replaced by per-objfile - data points implemented using "data" and "num_data" below. For - an example of how to use this replacement, see "objfile_data" - in "mips-tdep.c". */ - - void *deprecated_sym_private; - /* Per objfile data-pointers required by other GDB modules. */ - /* FIXME: kettenis/20030711: This mechanism could replace - deprecated_sym_stab_info and deprecated_sym_private - entirely. */ - void **data; - unsigned num_data; + REGISTRY_FIELDS; /* Set of relocation offsets to apply to each section. - Currently on the objfile_obstack (which makes no sense, but I'm - not sure it's harming anything). + The table is indexed by the_bfd_section->index, thus it is generally + as large as the number of sections in the binary. + The table is stored on the objfile_obstack. These offsets indicate that all symbols (including partial and minimal symbols) which have been read have been relocated by this - much. Symbols which are yet to be read need to be relocated by - it. */ + much. Symbols which are yet to be read need to be relocated by it. */ struct section_offsets *section_offsets; int num_sections; @@ -354,12 +354,11 @@ struct objfile among other things, is used to map pc addresses into sections. SECTIONS points to the first entry in the table, and SECTIONS_END points to the first location past the last entry - in the table. Currently the table is stored on the - objfile_obstack (which makes no sense, but I'm not sure it's - harming anything). */ + in the table. The table is stored on the objfile_obstack. + There is no particular order to the sections in this table, and it + only contains sections we care about (e.g. non-empty, SEC_ALLOC). */ - struct obj_section - *sections, *sections_end; + struct obj_section *sections, *sections_end; /* GDB allows to have debug symbols in separate object files. This is used by .gnu_debuglink, ELF build id note and Mach-O OSO. @@ -381,7 +380,7 @@ struct objfile struct objfile *separate_debug_objfile_link; /* Place to stash various statistics about this objfile. */ - OBJSTATS; + OBJSTATS; /* A linked list of symbols created when reading template types or function templates. These symbols are not stored in any symbol @@ -444,13 +443,11 @@ extern struct objfile *allocate_objfile (bfd *, int); extern struct gdbarch *get_objfile_arch (struct objfile *); -extern void init_entry_point_info (struct objfile *); - extern int entry_point_address_query (CORE_ADDR *entry_p); extern CORE_ADDR entry_point_address (void); -extern int build_objfile_section_table (struct objfile *); +extern void build_objfile_section_table (struct objfile *); extern void terminate_minimal_symbol_table (struct objfile *objfile); @@ -474,6 +471,7 @@ extern struct cleanup *make_cleanup_free_objfile (struct objfile *); extern void free_all_objfiles (void); extern void objfile_relocate (struct objfile *, struct section_offsets *); +extern void objfile_rebase (struct objfile *, CORE_ADDR); extern int objfile_has_partial_symbols (struct objfile *objfile); @@ -504,28 +502,12 @@ extern int in_plt_section (CORE_ADDR, char *); /* Keep a registry of per-objfile data-pointers required by other GDB modules. */ +DECLARE_REGISTRY(objfile); -/* Allocate an entry in the per-objfile registry. */ -extern const struct objfile_data *register_objfile_data (void); - -/* Allocate an entry in the per-objfile registry. - SAVE and FREE are called when clearing objfile data. - First all registered SAVE functions are called. - Then all registered FREE functions are called. - Either or both of SAVE, FREE may be NULL. */ -extern const struct objfile_data *register_objfile_data_with_cleanup - (void (*save) (struct objfile *, void *), - void (*free) (struct objfile *, void *)); - -extern void clear_objfile_data (struct objfile *objfile); -extern void set_objfile_data (struct objfile *objfile, - const struct objfile_data *data, void *value); -extern void *objfile_data (struct objfile *objfile, - const struct objfile_data *data); - -extern struct bfd *gdb_bfd_ref (struct bfd *abfd); -extern void gdb_bfd_unref (struct bfd *abfd); -extern int gdb_bfd_close_or_warn (struct bfd *abfd); +extern void default_iterate_over_objfiles_in_search_order + (struct gdbarch *gdbarch, + iterate_over_objfiles_in_search_order_cb_ftype *cb, + void *cb_data, struct objfile *current_objfile); /* Traverse all object files in the current program space. @@ -535,7 +517,7 @@ extern int gdb_bfd_close_or_warn (struct bfd *abfd); /* Traverse all object files in program space SS. */ #define ALL_PSPACE_OBJFILES(ss, obj) \ - for ((obj) = ss->objfiles; (obj) != NULL; (obj) = (obj)->next) \ + for ((obj) = ss->objfiles; (obj) != NULL; (obj) = (obj)->next) #define ALL_PSPACE_OBJFILES_SAFE(ss, obj, nxt) \ for ((obj) = ss->objfiles; \ @@ -557,6 +539,12 @@ extern int gdb_bfd_close_or_warn (struct bfd *abfd); #define ALL_OBJFILE_SYMTABS(objfile, s) \ for ((s) = (objfile) -> symtabs; (s) != NULL; (s) = (s) -> next) +/* Traverse all primary symtabs in one objfile. */ + +#define ALL_OBJFILE_PRIMARY_SYMTABS(objfile, s) \ + ALL_OBJFILE_SYMTABS ((objfile), (s)) \ + if ((s)->primary) + /* Traverse all minimal symbols in one objfile. */ #define ALL_OBJFILE_MSYMBOLS(objfile, m) \ @@ -579,13 +567,11 @@ extern int gdb_bfd_close_or_warn (struct bfd *abfd); #define ALL_PRIMARY_SYMTABS(objfile, s) \ ALL_OBJFILES (objfile) \ - ALL_OBJFILE_SYMTABS (objfile, s) \ - if ((s)->primary) + ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s) #define ALL_PSPACE_PRIMARY_SYMTABS(pspace, objfile, s) \ ALL_PSPACE_OBJFILES (ss, objfile) \ - ALL_OBJFILE_SYMTABS (objfile, s) \ - if ((s)->primary) + ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s) /* Traverse all minimal symbols in all objfiles in the current symbol space. */ @@ -662,4 +648,8 @@ extern int gdb_bfd_close_or_warn (struct bfd *abfd); #define MULTI_OBJFILE_P() (object_files && object_files->next) +/* Reset the per-BFD storage area on OBJ. */ + +void set_objfile_per_bfd (struct objfile *obj); + #endif /* !defined (OBJFILES_H) */ diff --git a/contrib/gdb-7/gdb/observer.c b/contrib/gdb-7/gdb/observer.c index 4944480df1..22ae42eb2b 100644 --- a/contrib/gdb-7/gdb/observer.c +++ b/contrib/gdb-7/gdb/observer.c @@ -1,6 +1,6 @@ /* GDB Notifications to Observers. - Copyright (C) 2003-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -54,7 +54,7 @@ #include "command.h" #include "gdbcmd.h" -static int observer_debug; +static unsigned int observer_debug; static void show_observer_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -181,6 +181,11 @@ int observer_test_first_observer = 0; int observer_test_second_observer = 0; int observer_test_third_observer = 0; +/* Provide prototypes to silence -Wmissing-prototypes. */ +extern void observer_test_first_notification_function (int arg); +extern void observer_test_second_notification_function (int arg); +extern void observer_test_third_notification_function (int arg); + void observer_test_first_notification_function (int arg) { @@ -204,14 +209,14 @@ extern initialize_file_ftype _initialize_observer; /* -Wmissing-prototypes */ void _initialize_observer (void) { - add_setshow_zinteger_cmd ("observer", class_maintenance, - &observer_debug, _("\ + add_setshow_zuinteger_cmd ("observer", class_maintenance, + &observer_debug, _("\ Set observer debugging."), _("\ Show observer debugging."), _("\ When non-zero, observer debugging is enabled."), - NULL, - show_observer_debug, - &setdebuglist, &showdebuglist); + NULL, + show_observer_debug, + &setdebuglist, &showdebuglist); } #include "observer.inc" diff --git a/contrib/gdb-7/gdb/observer.sh b/contrib/gdb-7/gdb/observer.sh index b5c49ac939..7b9e70cb26 100755 --- a/contrib/gdb-7/gdb/observer.sh +++ b/contrib/gdb-7/gdb/observer.sh @@ -29,7 +29,7 @@ rm -f ${otmp} cat <>${otmp} /* GDB Notifications to Observers. - Copyright (C) 2004-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -64,6 +64,7 @@ struct so_list; struct objfile; struct thread_info; struct inferior; +struct trace_state_variable; EOF ;; esac @@ -136,8 +137,17 @@ static void observer_${event}_notification_stub (const void *data, const void *args_data) { observer_${event}_ftype *notify = (observer_${event}_ftype *) data; +EOF + + notify_args=`echo ${actual} | sed -e 's/\([a-z0-9_][a-z0-9_]*\)/args->\1/g'` + + if test ! -z "${notify_args}"; then + cat<>${otmp} const struct ${event}_args *args = args_data; - notify (`echo ${actual} | sed -e 's/\([a-z0-9_][a-z0-9_]*\)/args->\1/g'`); +EOF + fi + cat <>${otmp} + notify (${notify_args}); } struct observer * diff --git a/contrib/gdb-7/gdb/opencl-lang.c b/contrib/gdb-7/gdb/opencl-lang.c index 6557a08f20..819a83202a 100644 --- a/contrib/gdb-7/gdb/opencl-lang.c +++ b/contrib/gdb-7/gdb/opencl-lang.c @@ -1,5 +1,5 @@ /* OpenCL language support for GDB, the GNU debugger. - Copyright (C) 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. Contributed by Ken Werner . @@ -68,7 +68,7 @@ enum opencl_primitive_types { static struct gdbarch_data *opencl_type_data; -struct type ** +static struct type ** builtin_opencl_type (struct gdbarch *gdbarch) { return gdbarch_data (gdbarch, opencl_type_data); @@ -683,6 +683,58 @@ vector_relop (struct expression *exp, struct value *val1, struct value *val2, return ret; } +/* Perform a cast of ARG into TYPE. There's sadly a lot of duplication in + here from valops.c:value_cast, opencl is different only in the + behaviour of scalar to vector casting. As far as possibly we're going + to try and delegate back to the standard value_cast function. */ + +static struct value * +opencl_value_cast (struct type *type, struct value *arg) +{ + if (type != value_type (arg)) + { + /* Casting scalar to vector is a special case for OpenCL, scalar + is cast to element type of vector then replicated into each + element of the vector. First though, we need to work out if + this is a scalar to vector cast; code lifted from + valops.c:value_cast. */ + enum type_code code1, code2; + struct type *to_type; + int scalar; + + to_type = check_typedef (type); + + code1 = TYPE_CODE (to_type); + code2 = TYPE_CODE (check_typedef (value_type (arg))); + + if (code2 == TYPE_CODE_REF) + code2 = TYPE_CODE (check_typedef (value_type (coerce_ref (arg)))); + + scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_BOOL + || code2 == TYPE_CODE_CHAR || code2 == TYPE_CODE_FLT + || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM + || code2 == TYPE_CODE_RANGE); + + if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (to_type) && scalar) + { + struct type *eltype; + + /* Cast to the element type of the vector here as + value_vector_widen will error if the scalar value is + truncated by the cast. To avoid the error, cast (and + possibly truncate) here. */ + eltype = check_typedef (TYPE_TARGET_TYPE (to_type)); + arg = value_cast (eltype, arg); + + return value_vector_widen (arg, type); + } + else + /* Standard cast handler. */ + arg = value_cast (type, arg); + } + return arg; +} + /* Perform a relational operation on two operands. */ static struct value * @@ -718,7 +770,7 @@ opencl_relop (struct expression *exp, struct value *arg1, struct value *arg2, if (TYPE_CODE (t) != TYPE_CODE_FLT && !is_integral_type (t)) error (_("Argument to operation not a number or boolean.")); - *v = value_cast (t1_is_vec ? type1 : type2, *v); + *v = opencl_value_cast (t1_is_vec ? type1 : type2, *v); val = vector_relop (exp, arg1, arg2, op); } @@ -740,6 +792,46 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp, switch (op) { + /* Handle assignment and cast operators to support OpenCL-style + scalar-to-vector widening. */ + case BINOP_ASSIGN: + (*pos)++; + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + type1 = value_type (arg1); + arg2 = evaluate_subexp (type1, exp, pos, noside); + + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + + if (deprecated_value_modifiable (arg1) + && VALUE_LVAL (arg1) != lval_internalvar) + arg2 = opencl_value_cast (type1, arg2); + + return value_assign (arg1, arg2); + + case UNOP_CAST: + type1 = exp->elts[*pos + 1].type; + (*pos) += 2; + arg1 = evaluate_subexp (type1, exp, pos, noside); + + if (noside == EVAL_SKIP) + return value_from_longest (builtin_type (exp->gdbarch)-> + builtin_int, 1); + + return opencl_value_cast (type1, arg1); + + case UNOP_CAST_TYPE: + (*pos)++; + arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + type1 = value_type (arg1); + arg1 = evaluate_subexp (type1, exp, pos, noside); + + if (noside == EVAL_SKIP) + return value_from_longest (builtin_type (exp->gdbarch)-> + builtin_int, 1); + + return opencl_value_cast (type1, arg1); + /* Handle binary relational and equality operators that are either not or differently defined for GNU vectors. */ case BINOP_EQUAL: @@ -852,12 +944,12 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp, /* Widen the scalar operand to a vector if necessary. */ if (t2_is_vec || !t3_is_vec) { - arg3 = value_cast (type2, arg3); + arg3 = opencl_value_cast (type2, arg3); type3 = value_type (arg3); } else if (!t2_is_vec || t3_is_vec) { - arg2 = value_cast (type3, arg2); + arg2 = opencl_value_cast (type3, arg2); type2 = value_type (arg2); } else if (!t2_is_vec || !t3_is_vec) @@ -961,7 +1053,28 @@ Cannot perform conditional operation on vectors with different sizes")); return evaluate_subexp_c (expect_type, exp, pos, noside); } -void +/* Print OpenCL types. */ + +static void +opencl_print_type (struct type *type, const char *varstring, + struct ui_file *stream, int show, int level, + const struct type_print_options *flags) +{ + /* We nearly always defer to C type printing, except that vector + types are considered primitive in OpenCL, and should always + be printed using their TYPE_NAME. */ + if (show > 0) + { + CHECK_TYPEDEF (type); + if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type) + && TYPE_NAME (type) != NULL) + show = 0; + } + + c_print_type (type, varstring, stream, show, level, flags); +} + +static void opencl_language_arch_info (struct gdbarch *gdbarch, struct language_arch_info *lai) { @@ -993,7 +1106,6 @@ const struct language_defn opencl_language_defn = "opencl", /* Language name */ language_opencl, range_check_off, - type_check_off, case_sensitive_on, array_row_major, macro_expansion_c, @@ -1004,10 +1116,11 @@ const struct language_defn opencl_language_defn = c_printchar, /* Print a character constant */ c_printstr, /* Function to print string constant */ c_emit_char, /* Print a single char */ - c_print_type, /* Print a type using appropriate syntax */ + opencl_print_type, /* Print a type using appropriate syntax */ c_print_typedef, /* Print a typedef using appropriate syntax */ c_val_print, /* Print a value using appropriate syntax */ c_value_print, /* Print a top-level value */ + default_read_var_value, /* la_read_var_value */ NULL, /* Language specific skip_trampoline */ NULL, /* name_of_this */ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ @@ -1024,7 +1137,7 @@ const struct language_defn opencl_language_defn = default_print_array_index, default_pass_by_reference, c_get_string, - strcmp_iw_ordered, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, LANG_MAGIC }; @@ -1116,6 +1229,9 @@ build_opencl_types (struct gdbarch *gdbarch) return types; } +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_opencl_language; + void _initialize_opencl_language (void) { diff --git a/contrib/gdb-7/gdb/osabi.c b/contrib/gdb-7/gdb/osabi.c index aba9842734..a123ea05bc 100644 --- a/contrib/gdb-7/gdb/osabi.c +++ b/contrib/gdb-7/gdb/osabi.c @@ -1,6 +1,6 @@ /* OS ABI variant handling for GDB. - Copyright (C) 2001-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -72,6 +72,9 @@ static const char * const gdb_osabi_names[] = "DICOS", "Darwin", "Symbian", + "OpenVMS", + "LynxOS178", + "Newlib", "" }; @@ -369,14 +372,23 @@ gdbarch_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch) /* Limit on the amount of data to be read. */ #define MAX_NOTESZ 128 -/* Return non-zero if NOTE matches NAME, DESCSZ and TYPE. */ +/* Return non-zero if NOTE matches NAME, DESCSZ and TYPE. If + *SECTSIZE is non-zero, then this reads that many bytes from + the start of the section and clears *SECTSIZE. */ static int -check_note (bfd *abfd, asection *sect, const char *note, +check_note (bfd *abfd, asection *sect, char *note, unsigned int *sectsize, const char *name, unsigned long descsz, unsigned long type) { unsigned long notesz; + if (*sectsize) + { + if (!bfd_get_section_contents (abfd, sect, note, 0, *sectsize)) + return 0; + *sectsize = 0; + } + /* Calculate the size of this note. */ notesz = strlen (name) + 1; notesz = ((notesz + 3) & ~3); @@ -423,14 +435,18 @@ generic_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, void *obj) if (sectsize > MAX_NOTESZ) sectsize = MAX_NOTESZ; + /* We lazily read the section data here. Since we use + BFD_DECOMPRESS, we can't use bfd_get_section_contents on a + compressed section. But, since note sections are not compressed, + deferring the reading until we recognize the section avoids any + error. */ note = alloca (sectsize); - bfd_get_section_contents (abfd, sect, note, 0, sectsize); /* .note.ABI-tag notes, used by GNU/Linux and FreeBSD. */ if (strcmp (name, ".note.ABI-tag") == 0) { /* GNU. */ - if (check_note (abfd, sect, note, "GNU", 16, NT_GNU_ABI_TAG)) + if (check_note (abfd, sect, note, §size, "GNU", 16, NT_GNU_ABI_TAG)) { unsigned int abi_tag = bfd_h_get_32 (abfd, note + 16); @@ -466,7 +482,8 @@ generic_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, void *obj) } /* FreeBSD. */ - if (check_note (abfd, sect, note, "FreeBSD", 4, NT_FREEBSD_ABI_TAG)) + if (check_note (abfd, sect, note, §size, "FreeBSD", 4, + NT_FREEBSD_ABI_TAG)) { /* There is no need to check the version yet. */ *osabi = GDB_OSABI_FREEBSD_ELF; @@ -478,7 +495,7 @@ generic_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, void *obj) /* .note.netbsd.ident notes, used by NetBSD. */ if (strcmp (name, ".note.netbsd.ident") == 0 - && check_note (abfd, sect, note, "NetBSD", 4, NT_NETBSD_IDENT)) + && check_note (abfd, sect, note, §size, "NetBSD", 4, NT_NETBSD_IDENT)) { /* There is no need to check the version yet. */ *osabi = GDB_OSABI_NETBSD_ELF; @@ -487,7 +504,8 @@ generic_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, void *obj) /* .note.openbsd.ident notes, used by OpenBSD. */ if (strcmp (name, ".note.openbsd.ident") == 0 - && check_note (abfd, sect, note, "OpenBSD", 4, NT_OPENBSD_IDENT)) + && check_note (abfd, sect, note, §size, "OpenBSD", 4, + NT_OPENBSD_IDENT)) { /* There is no need to check the version yet. */ *osabi = GDB_OSABI_OPENBSD_ELF; @@ -549,6 +567,10 @@ generic_elf_osabi_sniffer (bfd *abfd) generic_elf_osabi_sniff_abi_tag_sections, &osabi); break; + + case ELFOSABI_OPENVMS: + osabi = GDB_OSABI_OPENVMS; + break; } if (osabi == GDB_OSABI_UNKNOWN) diff --git a/contrib/gdb-7/gdb/osabi.h b/contrib/gdb-7/gdb/osabi.h index ced2fa5c5b..fd5b15142f 100644 --- a/contrib/gdb-7/gdb/osabi.h +++ b/contrib/gdb-7/gdb/osabi.h @@ -1,5 +1,5 @@ /* OS ABI variant handling for GDB. - Copyright (C) 2001-2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/osdata.c b/contrib/gdb-7/gdb/osdata.c index 62ce412ca6..a19b21d2f5 100644 --- a/contrib/gdb-7/gdb/osdata.c +++ b/contrib/gdb-7/gdb/osdata.c @@ -1,6 +1,6 @@ /* Routines for handling XML generic OS data provided by target. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -288,7 +288,7 @@ get_osdata_column (struct osdata_item *item, const char *name) return NULL; } -static void +void info_osdata_command (char *type, int from_tty) { struct ui_out *uiout = current_uiout; @@ -297,6 +297,7 @@ info_osdata_command (char *type, int from_tty) struct cleanup *old_chain; int ncols = 0; int nrows; + int col_to_skip = -1; osdata = get_osdata (type); old_chain = make_cleanup_osdata_free (osdata); @@ -311,6 +312,28 @@ info_osdata_command (char *type, int from_tty) last = VEC_last (osdata_item_s, osdata->items); if (last->columns) ncols = VEC_length (osdata_column_s, last->columns); + + /* As a special case, scan the listing of available data types + for a column named "Title", and only include it with MI + output; this column's normal use is for titles for interface + elements like menus, and it clutters up CLI output. */ + if (!type && !ui_out_is_mi_like_p (uiout)) + { + struct osdata_column *col; + int ix; + + for (ix = 0; + VEC_iterate (osdata_column_s, last->columns, ix, col); + ix++) + { + if (strcmp (col->name, "Title") == 0) + col_to_skip = ix; + } + /* Be sure to reduce the total column count, otherwise + internal errors ensue. */ + if (col_to_skip >= 0) + --ncols; + } } make_cleanup_ui_out_table_begin_end (uiout, ncols, nrows, @@ -335,7 +358,10 @@ info_osdata_command (char *type, int from_tty) ix++) { char col_name[32]; - + + if (ix == col_to_skip) + continue; + snprintf (col_name, 32, "col%d", ix); ui_out_table_header (uiout, 10, ui_left, col_name, col->name); @@ -355,13 +381,10 @@ info_osdata_command (char *type, int from_tty) ix_items++) { struct cleanup *old_chain; - struct ui_stream *stb; int ix_cols; struct osdata_column *col; - stb = ui_out_stream_new (uiout); - old_chain = make_cleanup_ui_out_stream_delete (stb); - make_cleanup_ui_out_tuple_begin_end (uiout, "item"); + old_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "item"); for (ix_cols = 0; VEC_iterate (osdata_column_s, item->columns, @@ -369,7 +392,10 @@ info_osdata_command (char *type, int from_tty) ix_cols++) { char col_name[32]; - + + if (ix_cols == col_to_skip) + continue; + snprintf (col_name, 32, "col%d", ix_cols); ui_out_field_string (uiout, col_name, col->value); } diff --git a/contrib/gdb-7/gdb/osdata.h b/contrib/gdb-7/gdb/osdata.h index f63b0f3f19..1664c1cc7f 100644 --- a/contrib/gdb-7/gdb/osdata.h +++ b/contrib/gdb-7/gdb/osdata.h @@ -1,6 +1,6 @@ /* Routines for handling XML generic OS data provided by target. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -49,5 +49,6 @@ void osdata_free (struct osdata *); struct cleanup *make_cleanup_osdata_free (struct osdata *data); struct osdata *get_osdata (const char *type); const char *get_osdata_column (struct osdata_item *item, const char *name); +void info_osdata_command (char *type, int from_tty); #endif /* OSDATA_H */ diff --git a/contrib/gdb-7/gdb/p-exp.y b/contrib/gdb-7/gdb/p-exp.y index 7b05d585f5..a989ac4ca5 100644 --- a/contrib/gdb-7/gdb/p-exp.y +++ b/contrib/gdb-7/gdb/p-exp.y @@ -1,5 +1,5 @@ /* YACC parser for Pascal expressions, for GDB. - Copyright (C) 2000, 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -105,6 +105,12 @@ #define yygindex pascal_yygindex #define yytable pascal_yytable #define yycheck pascal_yycheck +#define yyss pascal_yyss +#define yysslim pascal_yysslim +#define yyssp pascal_yyssp +#define yystacksize pascal_yystacksize +#define yyvs pascal_yyvs +#define yyvsp pascal_yyvsp #ifndef YYDEBUG #define YYDEBUG 1 /* Default to yydebug support */ @@ -338,7 +344,7 @@ exp : field_exp COMPLETE exp : exp '[' /* We need to save the current_type value. */ - { char *arrayname; + { const char *arrayname; int arrayfieldindex; arrayfieldindex = is_pascal_string_type ( current_type, NULL, NULL, @@ -652,7 +658,7 @@ block : BLOCKNAME block : block COLONCOLON name { struct symbol *tem = lookup_symbol (copy_name ($3), $1, - VAR_DOMAIN, (int *) NULL); + VAR_DOMAIN, NULL); if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) error (_("No function \"%s\" in specified context."), copy_name ($3)); @@ -662,7 +668,7 @@ block : block COLONCOLON name variable: block COLONCOLON name { struct symbol *sym; sym = lookup_symbol (copy_name ($3), $1, - VAR_DOMAIN, (int *) NULL); + VAR_DOMAIN, NULL); if (sym == 0) error (_("No symbol \"%s\" in specified context."), copy_name ($3)); @@ -698,7 +704,7 @@ variable: qualified_name sym = lookup_symbol (name, (const struct block *) NULL, - VAR_DOMAIN, (int *) NULL); + VAR_DOMAIN, NULL); if (sym) { write_exp_elt_opcode (OP_VAR_VALUE); @@ -1093,9 +1099,8 @@ static const struct token tokentab2[] = /* Allocate uppercased var: */ /* make an uppercased copy of tokstart. */ -static char * uptok (tokstart, namelen) - char *tokstart; - int namelen; +static char * +uptok (char *tokstart, int namelen) { int i; char *uptokstart = (char *)malloc(namelen+1); @@ -1232,7 +1237,7 @@ yylex (void) /* Might be a floating point number. */ if (lexptr[1] < '0' || lexptr[1] > '9') { - if (in_parse_field) + if (parse_completion) last_was_structop = 1; goto symbol; /* Nope, must be a symbol. */ } @@ -1478,7 +1483,7 @@ yylex (void) static const char this_name[] = "this"; if (lookup_symbol (this_name, expression_context_block, - VAR_DOMAIN, (int *) NULL)) + VAR_DOMAIN, NULL)) { free (uptokstart); return THIS; @@ -1517,20 +1522,20 @@ yylex (void) { char *tmp = copy_name (yylval.sval); struct symbol *sym; - int is_a_field_of_this = 0; + struct field_of_this_result is_a_field_of_this; int is_a_field = 0; int hextype; if (search_field && current_type) is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL); - if (is_a_field || in_parse_field) + if (is_a_field || parse_completion) sym = NULL; else sym = lookup_symbol (tmp, expression_context_block, VAR_DOMAIN, &is_a_field_of_this); /* second chance uppercased (as Free Pascal does). */ - if (!sym && !is_a_field_of_this && !is_a_field) + if (!sym && is_a_field_of_this.type == NULL && !is_a_field) { for (i = 0; i <= namelen; i++) { @@ -1539,12 +1544,12 @@ yylex (void) } if (search_field && current_type) is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL); - if (is_a_field || in_parse_field) + if (is_a_field || parse_completion) sym = NULL; else sym = lookup_symbol (tmp, expression_context_block, VAR_DOMAIN, &is_a_field_of_this); - if (sym || is_a_field_of_this || is_a_field) + if (sym || is_a_field_of_this.type != NULL || is_a_field) for (i = 0; i <= namelen; i++) { if ((tokstart[i] >= 'a' && tokstart[i] <= 'z')) @@ -1552,7 +1557,7 @@ yylex (void) } } /* Third chance Capitalized (as GPC does). */ - if (!sym && !is_a_field_of_this && !is_a_field) + if (!sym && is_a_field_of_this.type == NULL && !is_a_field) { for (i = 0; i <= namelen; i++) { @@ -1567,12 +1572,12 @@ yylex (void) } if (search_field && current_type) is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL); - if (is_a_field || in_parse_field) + if (is_a_field || parse_completion) sym = NULL; else sym = lookup_symbol (tmp, expression_context_block, VAR_DOMAIN, &is_a_field_of_this); - if (sym || is_a_field_of_this || is_a_field) + if (sym || is_a_field_of_this.type != NULL || is_a_field) for (i = 0; i <= namelen; i++) { if (i == 0) @@ -1602,7 +1607,7 @@ yylex (void) || lookup_symtab (tmp)) { yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; + yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL; free (uptokstart); return BLOCKNAME; } @@ -1668,7 +1673,7 @@ yylex (void) memcpy (tmp1, namestart, p - namestart); tmp1[p - namestart] = '\0'; cur_sym = lookup_symbol (ncopy, expression_context_block, - VAR_DOMAIN, (int *) NULL); + VAR_DOMAIN, NULL); if (cur_sym) { if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF) @@ -1717,7 +1722,7 @@ yylex (void) if (hextype == INT) { yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; + yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL; free (uptokstart); return NAME_OR_INT; } @@ -1726,14 +1731,13 @@ yylex (void) free(uptokstart); /* Any other kind of symbol. */ yylval.ssym.sym = sym; - yylval.ssym.is_a_field_of_this = is_a_field_of_this; + yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL; return NAME; } } void -yyerror (msg) - char *msg; +yyerror (char *msg) { if (prev_lexptr) lexptr = prev_lexptr; diff --git a/contrib/gdb-7/gdb/p-lang.c b/contrib/gdb-7/gdb/p-lang.c index cd56630efd..07006cd079 100644 --- a/contrib/gdb-7/gdb/p-lang.c +++ b/contrib/gdb-7/gdb/p-lang.c @@ -1,7 +1,6 @@ /* Pascal language support routines for GDB, the GNU debugger. - Copyright (C) 2000, 2002-2005, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -99,7 +98,7 @@ int is_pascal_string_type (struct type *type,int *length_pos, int *length_size, int *string_pos, struct type **char_type, - char **arrayname) + const char **arrayname) { if (type != NULL && TYPE_CODE (type) == TYPE_CODE_STRUCT) { @@ -280,10 +279,7 @@ pascal_printstr (struct ui_file *stream, struct type *type, { if (in_quotes) { - if (options->inspect_it) - fputs_filtered ("\\', ", stream); - else - fputs_filtered ("', ", stream); + fputs_filtered ("', ", stream); in_quotes = 0; } pascal_printchar (current_char, type, stream); @@ -296,10 +292,7 @@ pascal_printstr (struct ui_file *stream, struct type *type, { if ((!in_quotes) && (PRINT_LITERAL_FORM (current_char))) { - if (options->inspect_it) - fputs_filtered ("\\'", stream); - else - fputs_filtered ("'", stream); + fputs_filtered ("'", stream); in_quotes = 1; } pascal_one_char (current_char, stream, &in_quotes); @@ -309,12 +302,7 @@ pascal_printstr (struct ui_file *stream, struct type *type, /* Terminate the quotes if necessary. */ if (in_quotes) - { - if (options->inspect_it) - fputs_filtered ("\\'", stream); - else - fputs_filtered ("'", stream); - } + fputs_filtered ("'", stream); if (force_ellipses || i < length) fputs_filtered ("...", stream); @@ -429,7 +417,6 @@ const struct language_defn pascal_language_defn = "pascal", /* Language name */ language_pascal, range_check_on, - type_check_on, case_sensitive_on, array_row_major, macro_expansion_no, @@ -444,6 +431,7 @@ const struct language_defn pascal_language_defn = pascal_print_typedef, /* Print a typedef using appropriate syntax */ pascal_val_print, /* Print a value using appropriate syntax */ pascal_value_print, /* Print a top-level value */ + default_read_var_value, /* la_read_var_value */ NULL, /* Language specific skip_trampoline */ "this", /* name_of_this */ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ @@ -459,7 +447,7 @@ const struct language_defn pascal_language_defn = default_print_array_index, default_pass_by_reference, default_get_string, - strcmp_iw_ordered, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, LANG_MAGIC }; diff --git a/contrib/gdb-7/gdb/p-lang.h b/contrib/gdb-7/gdb/p-lang.h index 308b7b50dd..74d5d539ee 100644 --- a/contrib/gdb-7/gdb/p-lang.h +++ b/contrib/gdb-7/gdb/p-lang.h @@ -1,6 +1,6 @@ /* Pascal language support definitions for GDB, the GNU debugger. - Copyright (C) 2000, 2005-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -30,18 +30,18 @@ extern void pascal_error (char *); /* Defined in p-exp.y */ /* Defined in p-typeprint.c */ extern void pascal_print_type (struct type *, const char *, struct ui_file *, - int, int); + int, int, const struct type_print_options *); extern void pascal_print_typedef (struct type *, struct symbol *, struct ui_file *); -extern int pascal_val_print (struct type *, const gdb_byte *, int, - CORE_ADDR, struct ui_file *, int, - const struct value *, - const struct value_print_options *); +extern void pascal_val_print (struct type *, const gdb_byte *, int, + CORE_ADDR, struct ui_file *, int, + const struct value *, + const struct value_print_options *); -extern int pascal_value_print (struct value *, struct ui_file *, - const struct value_print_options *); +extern void pascal_value_print (struct value *, struct ui_file *, + const struct value_print_options *); extern void pascal_type_print_method_args (const char *, const char *, struct ui_file *); @@ -50,7 +50,7 @@ extern void pascal_type_print_method_args (const char *, const char *, extern int is_pascal_string_type (struct type *, int *, int *, int *, - struct type **, char **); + struct type **, const char **); extern void pascal_printchar (int, struct type *, struct ui_file *); @@ -63,10 +63,12 @@ extern struct type **const (pascal_builtin_types[]); /* These are in p-typeprint.c: */ extern void - pascal_type_print_base (struct type *, struct ui_file *, int, int); + pascal_type_print_base (struct type *, struct ui_file *, int, int, + const struct type_print_options *); extern void - pascal_type_print_varspec_prefix (struct type *, struct ui_file *, int, int); + pascal_type_print_varspec_prefix (struct type *, struct ui_file *, int, int, + const struct type_print_options *); extern void pascal_object_print_value_fields (struct type *, const gdb_byte *, int, diff --git a/contrib/gdb-7/gdb/p-typeprint.c b/contrib/gdb-7/gdb/p-typeprint.c index dae56d3a04..30d40d788d 100644 --- a/contrib/gdb-7/gdb/p-typeprint.c +++ b/contrib/gdb-7/gdb/p-typeprint.c @@ -1,5 +1,5 @@ /* Support for printing Pascal types for GDB, the GNU debugger. - Copyright (C) 2000-2002, 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -36,20 +36,20 @@ #include static void pascal_type_print_varspec_suffix (struct type *, struct ui_file *, - int, int, int); + int, int, int, + const struct type_print_options *); static void pascal_type_print_derivation_info (struct ui_file *, struct type *); -void pascal_type_print_varspec_prefix (struct type *, struct ui_file *, - int, int); /* LEVEL is the depth to indent lines by. */ void pascal_print_type (struct type *type, const char *varstring, - struct ui_file *stream, int show, int level) + struct ui_file *stream, int show, int level, + const struct type_print_options *flags) { enum type_code code; int demangled_args; @@ -62,7 +62,7 @@ pascal_print_type (struct type *type, const char *varstring, if ((code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)) { - pascal_type_print_varspec_prefix (type, stream, show, 0); + pascal_type_print_varspec_prefix (type, stream, show, 0, flags); } /* first the name */ fputs_filtered (varstring, stream); @@ -77,15 +77,16 @@ pascal_print_type (struct type *type, const char *varstring, if (!(code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)) { - pascal_type_print_varspec_prefix (type, stream, show, 0); + pascal_type_print_varspec_prefix (type, stream, show, 0, flags); } - pascal_type_print_base (type, stream, show, level); + pascal_type_print_base (type, stream, show, level, flags); /* For demangled function names, we have the arglist as part of the name, so don't print an additional pair of ()'s. */ demangled_args = varstring ? strchr (varstring, '(') != NULL : 0; - pascal_type_print_varspec_suffix (type, stream, show, 0, demangled_args); + pascal_type_print_varspec_suffix (type, stream, show, 0, demangled_args, + flags); } @@ -131,7 +132,7 @@ pascal_print_typedef (struct type *type, struct symbol *new_symbol, static void pascal_type_print_derivation_info (struct ui_file *stream, struct type *type) { - char *name; + const char *name; int i; for (i = 0; i < TYPE_N_BASECLASSES (type); i++) @@ -205,7 +206,8 @@ pascal_type_print_method_args (const char *physname, const char *methodname, void pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream, - int show, int passed_a_ptr) + int show, int passed_a_ptr, + const struct type_print_options *flags) { if (type == 0) return; @@ -219,7 +221,8 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream, { case TYPE_CODE_PTR: fprintf_filtered (stream, "^"); - pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1, + flags); break; /* Pointer should be handled normally in pascal. */ @@ -239,13 +242,14 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream, { fprintf_filtered (stream, " "); pascal_type_print_base (TYPE_DOMAIN_TYPE (type), - stream, 0, passed_a_ptr); + stream, 0, passed_a_ptr, flags); fprintf_filtered (stream, "::"); } break; case TYPE_CODE_REF: - pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1, + flags); fprintf_filtered (stream, "&"); break; @@ -289,7 +293,6 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream, case TYPE_CODE_SET: case TYPE_CODE_RANGE: case TYPE_CODE_STRING: - case TYPE_CODE_BITSTRING: case TYPE_CODE_COMPLEX: case TYPE_CODE_TYPEDEF: /* These types need no prefix. They are listed here so that @@ -302,7 +305,8 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream, } static void -pascal_print_func_args (struct type *type, struct ui_file *stream) +pascal_print_func_args (struct type *type, struct ui_file *stream, + const struct type_print_options *flags) { int i, len = TYPE_NFIELDS (type); @@ -324,7 +328,7 @@ pascal_print_func_args (struct type *type, struct ui_file *stream) } */ pascal_print_type (TYPE_FIELD_TYPE (type, i), "" /* TYPE_FIELD_NAME seems invalid! */ - ,stream, -1, 0); + ,stream, -1, 0, flags); } if (len) { @@ -339,7 +343,8 @@ pascal_print_func_args (struct type *type, struct ui_file *stream) static void pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream, int show, int passed_a_ptr, - int demangled_args) + int demangled_args, + const struct type_print_options *flags) { if (type == 0) return; @@ -366,32 +371,34 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream, { fprintf_filtered (stream, " : "); pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, 0, 0); - pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0); + stream, 0, 0, flags); + pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0, + flags); pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, - passed_a_ptr, 0); + passed_a_ptr, 0, flags); } break; case TYPE_CODE_PTR: case TYPE_CODE_REF: pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), - stream, 0, 1, 0); + stream, 0, 1, 0, flags); break; case TYPE_CODE_FUNC: if (passed_a_ptr) fprintf_filtered (stream, ")"); if (!demangled_args) - pascal_print_func_args (type, stream); + pascal_print_func_args (type, stream, flags); if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID) { fprintf_filtered (stream, " : "); pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), - stream, 0, 0); - pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0); + stream, 0, 0, flags); + pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0, + flags); pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, - passed_a_ptr, 0); + passed_a_ptr, 0, flags); } break; @@ -408,7 +415,6 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream, case TYPE_CODE_SET: case TYPE_CODE_RANGE: case TYPE_CODE_STRING: - case TYPE_CODE_BITSTRING: case TYPE_CODE_COMPLEX: case TYPE_CODE_TYPEDEF: /* These types do not need a suffix. They are listed so that @@ -438,11 +444,11 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream, void pascal_type_print_base (struct type *type, struct ui_file *stream, int show, - int level) + int level, const struct type_print_options *flags) { int i; int len; - int lastval; + LONGEST lastval; enum { s_none, s_public, s_private, s_protected @@ -484,7 +490,8 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show, case TYPE_CODE_REF: /* case TYPE_CODE_FUNC: case TYPE_CODE_METHOD: */ - pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level, + flags); break; case TYPE_CODE_ARRAY: @@ -494,7 +501,7 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show, stream, show, level); pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); */ - pascal_print_type (TYPE_TARGET_TYPE (type), NULL, stream, 0, 0); + pascal_print_type (TYPE_TARGET_TYPE (type), NULL, stream, 0, 0, flags); break; case TYPE_CODE_FUNC: @@ -603,7 +610,7 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show, fprintf_filtered (stream, "static "); pascal_print_type (TYPE_FIELD_TYPE (type, i), TYPE_FIELD_NAME (type, i), - stream, show - 1, level + 4); + stream, show - 1, level + 4, flags); if (!field_is_static (&TYPE_FIELD (type, i)) && TYPE_FIELD_PACKED (type, i)) { @@ -629,7 +636,7 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show, { struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i); - char *method_name = TYPE_FN_FIELDLIST_NAME (type, i); + const char *method_name = TYPE_FN_FIELDLIST_NAME (type, i); /* this is GNU C++ specific how can we know constructor/destructor? @@ -750,11 +757,12 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show, fprintf_filtered (stream, ", "); wrap_here (" "); fputs_filtered (TYPE_FIELD_NAME (type, i), stream); - if (lastval != TYPE_FIELD_BITPOS (type, i)) + if (lastval != TYPE_FIELD_ENUMVAL (type, i)) { fprintf_filtered (stream, - " := %d", TYPE_FIELD_BITPOS (type, i)); - lastval = TYPE_FIELD_BITPOS (type, i); + " := %s", + plongest (TYPE_FIELD_ENUMVAL (type, i))); + lastval = TYPE_FIELD_ENUMVAL (type, i); } lastval++; } @@ -788,11 +796,7 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show, case TYPE_CODE_SET: fputs_filtered ("set of ", stream); pascal_print_type (TYPE_INDEX_TYPE (type), "", stream, - show - 1, level); - break; - - case TYPE_CODE_BITSTRING: - fputs_filtered ("BitString", stream); + show - 1, level, flags); break; case TYPE_CODE_STRING: diff --git a/contrib/gdb-7/gdb/p-valprint.c b/contrib/gdb-7/gdb/p-valprint.c index c5bef8a0ff..bcc055ee8a 100644 --- a/contrib/gdb-7/gdb/p-valprint.c +++ b/contrib/gdb-7/gdb/p-valprint.c @@ -1,7 +1,6 @@ /* Support for printing Pascal values for GDB, the GNU debugger. - Copyright (C) 2000-2001, 2003, 2005-2012 Free Software Foundation, - Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -41,11 +40,22 @@ #include "exceptions.h" +/* Decorations for Pascal. */ + +static const struct generic_val_print_decorations p_decorations = +{ + "", + " + ", + " * I", + "true", + "false", + "void" +}; + /* See val_print for a description of the various parameters of this - function; they are identical. The semantics of the return value is - also identical to val_print. */ + function; they are identical. */ -int +void pascal_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR address, struct ui_file *stream, int recurse, @@ -61,8 +71,8 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, unsigned eltlen; int length_pos, length_size, string_pos; struct type *char_type; - LONGEST val; CORE_ADDR addr; + int want_space = 0; CHECK_TYPEDEF (type); switch (TYPE_CODE (type)) @@ -146,7 +156,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, /* Extract the address, assume that it is unsigned. */ addr = extract_unsigned_integer (valaddr + embedded_offset, TYPE_LENGTH (type), byte_order); - print_address_demangle (gdbarch, addr, stream, demangle); + print_address_demangle (options, gdbarch, addr, stream, demangle); break; } check_typedef (TYPE_TARGET_TYPE (type)); @@ -158,14 +168,14 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, if (TYPE_CODE (elttype) == TYPE_CODE_FUNC) { /* Try to print what function it points to. */ - print_address_demangle (gdbarch, addr, stream, demangle); - /* Return value is irrelevant except for string pointers. */ - return (0); + print_address_demangle (options, gdbarch, addr, stream, demangle); + return; } if (options->addressprint && options->format != 's') { fputs_filtered (paddress (gdbarch, addr), stream); + want_space = 1; } /* For a pointer to char or unsigned char, also print the string @@ -178,6 +188,8 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, && (options->format == 0 || options->format == 's') && addr != 0) { + if (want_space) + fputs_filtered (" ", stream); /* No wide string yet. */ i = val_print_string (elttype, NULL, addr, -1, stream, options); } @@ -193,6 +205,8 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, ULONGEST string_length; void *buffer; + if (want_space) + fputs_filtered (" ", stream); buffer = xmalloc (length_size); read_memory (addr + length_pos, buffer, length_size); string_length = extract_unsigned_integer (buffer, length_size, @@ -210,12 +224,17 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (vt_address); - if ((msymbol != NULL) + /* If 'symbol_print' is set, we did the work above. */ + if (!options->symbol_print + && (msymbol != NULL) && (vt_address == SYMBOL_VALUE_ADDRESS (msymbol))) { - fputs_filtered (" <", stream); + if (want_space) + fputs_filtered (" ", stream); + fputs_filtered ("<", stream); fputs_filtered (SYMBOL_PRINT_NAME (msymbol), stream); fputs_filtered (">", stream); + want_space = 1; } if (vt_address && options->vtblprint) { @@ -223,7 +242,10 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, struct symbol *wsym = (struct symbol *) NULL; struct type *wtype; struct block *block = (struct block *) NULL; - int is_this_fld; + struct field_of_this_result is_this_fld; + + if (want_space) + fputs_filtered (" ", stream); if (msymbol != NULL) wsym = lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol), block, @@ -248,50 +270,23 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, } } - /* Return number of characters printed, including the terminating - '\0' if we reached the end. val_print_string takes care including - the terminating '\0' if necessary. */ - return i; - - break; + return; case TYPE_CODE_REF: - elttype = check_typedef (TYPE_TARGET_TYPE (type)); - if (options->addressprint) - { - CORE_ADDR addr - = extract_typed_address (valaddr + embedded_offset, type); - - fprintf_filtered (stream, "@"); - fputs_filtered (paddress (gdbarch, addr), stream); - if (options->deref_ref) - fputs_filtered (": ", stream); - } - /* De-reference the reference. */ - if (options->deref_ref) - { - if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF) - { - struct value *deref_val; - - deref_val = coerce_ref_if_computed (original_value); - if (deref_val != NULL) - { - /* More complicated computed references are not supported. */ - gdb_assert (embedded_offset == 0); - } - else - deref_val = value_at (TYPE_TARGET_TYPE (type), - unpack_pointer (type, - (valaddr - + embedded_offset))); - - common_val_print (deref_val, stream, recurse + 1, options, - current_language); - } - else - fputs_filtered ("???", stream); - } + case TYPE_CODE_ENUM: + case TYPE_CODE_FLAGS: + case TYPE_CODE_FUNC: + case TYPE_CODE_RANGE: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_UNDEF: + case TYPE_CODE_BOOL: + case TYPE_CODE_CHAR: + generic_val_print (type, valaddr, embedded_offset, address, + stream, recurse, original_value, options, + &p_decorations); break; case TYPE_CODE_UNION: @@ -309,7 +304,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, -fvtable_thunks. (Otherwise, look under TYPE_CODE_PTR.) */ /* Extract the address, assume that it is unsigned. */ print_address_demangle - (gdbarch, + (options, gdbarch, extract_unsigned_integer (valaddr + embedded_offset + TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8, @@ -338,143 +333,6 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, } break; - case TYPE_CODE_ENUM: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - break; - } - len = TYPE_NFIELDS (type); - val = unpack_long (type, valaddr + embedded_offset); - for (i = 0; i < len; i++) - { - QUIT; - if (val == TYPE_FIELD_BITPOS (type, i)) - { - break; - } - } - if (i < len) - { - fputs_filtered (TYPE_FIELD_NAME (type, i), stream); - } - else - { - print_longest (stream, 'd', 0, val); - } - break; - - case TYPE_CODE_FLAGS: - if (options->format) - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - else - val_print_type_code_flags (type, valaddr + embedded_offset, stream); - break; - - case TYPE_CODE_FUNC: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - break; - } - /* FIXME, we should consider, at least for ANSI C language, eliminating - the distinction made between FUNCs and POINTERs to FUNCs. */ - fprintf_filtered (stream, "{"); - type_print (type, "", stream, -1); - fprintf_filtered (stream, "} "); - /* Try to print what function it points to, and its address. */ - print_address_demangle (gdbarch, address, stream, demangle); - break; - - case TYPE_CODE_BOOL: - if (options->format || options->output_format) - { - struct value_print_options opts = *options; - - opts.format = (options->format ? options->format - : options->output_format); - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, &opts, 0, stream); - } - else - { - val = unpack_long (type, valaddr + embedded_offset); - if (val == 0) - fputs_filtered ("false", stream); - else if (val == 1) - fputs_filtered ("true", stream); - else - { - fputs_filtered ("true (", stream); - fprintf_filtered (stream, "%ld)", (long int) val); - } - } - break; - - case TYPE_CODE_RANGE: - /* FIXME: create_range_type does not set the unsigned bit in a - range type (I think it probably should copy it from the target - type), so we won't print values which are too large to - fit in a signed integer correctly. */ - /* FIXME: Doesn't handle ranges of enums correctly. (Can't just - print with the target type, though, because the size of our type - and the target type might differ). */ - /* FALLTHROUGH */ - - case TYPE_CODE_INT: - if (options->format || options->output_format) - { - struct value_print_options opts = *options; - - opts.format = (options->format ? options->format - : options->output_format); - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, &opts, 0, stream); - } - else - { - val_print_type_code_int (type, valaddr + embedded_offset, stream); - } - break; - - case TYPE_CODE_CHAR: - if (options->format || options->output_format) - { - struct value_print_options opts = *options; - - opts.format = (options->format ? options->format - : options->output_format); - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, &opts, 0, stream); - } - else - { - val = unpack_long (type, valaddr + embedded_offset); - if (TYPE_UNSIGNED (type)) - fprintf_filtered (stream, "%u", (unsigned int) val); - else - fprintf_filtered (stream, "%d", (int) val); - fputs_filtered (" ", stream); - LA_PRINT_CHAR ((unsigned char) val, type, stream); - } - break; - - case TYPE_CODE_FLT: - if (options->format) - { - val_print_scalar_formatted (type, valaddr, embedded_offset, - original_value, options, 0, stream); - } - else - { - print_floating (valaddr + embedded_offset, type, stream); - } - break; - - case TYPE_CODE_BITSTRING: case TYPE_CODE_SET: elttype = TYPE_INDEX_TYPE (type); CHECK_TYPEDEF (elttype); @@ -489,13 +347,9 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, struct type *range = elttype; LONGEST low_bound, high_bound; int i; - int is_bitstring = TYPE_CODE (type) == TYPE_CODE_BITSTRING; int need_comma = 0; - if (is_bitstring) - fputs_filtered ("B'", stream); - else - fputs_filtered ("[", stream); + fputs_filtered ("[", stream); i = get_discrete_bounds (range, &low_bound, &high_bound); if (low_bound == 0 && high_bound == -1 && TYPE_LENGTH (type) > 0) @@ -523,9 +377,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, i = element; goto maybe_bad_bstring; } - if (is_bitstring) - fprintf_filtered (stream, "%d", element); - else if (element) + if (element) { if (need_comma) fputs_filtered (", ", stream); @@ -549,37 +401,18 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, } } done: - if (is_bitstring) - fputs_filtered ("'", stream); - else - fputs_filtered ("]", stream); + fputs_filtered ("]", stream); } break; - case TYPE_CODE_VOID: - fprintf_filtered (stream, "void"); - break; - - case TYPE_CODE_ERROR: - fprintf_filtered (stream, "%s", TYPE_ERROR_NAME (type)); - break; - - case TYPE_CODE_UNDEF: - /* This happens (without TYPE_FLAG_STUB set) on systems which don't use - dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar" - and no complete type for struct foo in that file. */ - fprintf_filtered (stream, ""); - break; - default: error (_("Invalid pascal type code %d in symbol table."), TYPE_CODE (type)); } gdb_flush (stream); - return (0); } -int +void pascal_value_print (struct value *val, struct ui_file *stream, const struct value_print_options *options) { @@ -613,7 +446,7 @@ pascal_value_print (struct value *val, struct ui_file *stream, fprintf_filtered (stream, ") "); } } - return common_val_print (val, stream, 0, &opts, current_language); + common_val_print (val, stream, 0, &opts, current_language); } @@ -649,7 +482,7 @@ const char pascal_vtbl_ptr_name[] = int pascal_object_is_vtbl_ptr_type (struct type *type) { - char *typename = type_name_no_tag (type); + const char *typename = type_name_no_tag (type); return (typename != NULL && strcmp (typename, pascal_vtbl_ptr_name) == 0); @@ -761,36 +594,17 @@ pascal_object_print_value_fields (struct type *type, const gdb_byte *valaddr, { wrap_here (n_spaces (2 + 2 * recurse)); } - if (options->inspect_it) - { - if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR) - fputs_filtered ("\"( ptr \"", stream); - else - fputs_filtered ("\"( nodef \"", stream); - if (field_is_static (&TYPE_FIELD (type, i))) - fputs_filtered ("static ", stream); - fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), - language_cplus, - DMGL_PARAMS | DMGL_ANSI); - fputs_filtered ("\" \"", stream); - fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), - language_cplus, - DMGL_PARAMS | DMGL_ANSI); - fputs_filtered ("\") \"", stream); - } - else - { - annotate_field_begin (TYPE_FIELD_TYPE (type, i)); - - if (field_is_static (&TYPE_FIELD (type, i))) - fputs_filtered ("static ", stream); - fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), - language_cplus, - DMGL_PARAMS | DMGL_ANSI); - annotate_field_name_end (); - fputs_filtered (" = ", stream); - annotate_field_value (); - } + + annotate_field_begin (TYPE_FIELD_TYPE (type, i)); + + if (field_is_static (&TYPE_FIELD (type, i))) + fputs_filtered ("static ", stream); + fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), + language_cplus, + DMGL_PARAMS | DMGL_ANSI); + annotate_field_name_end (); + fputs_filtered (" = ", stream); + annotate_field_value (); if (!field_is_static (&TYPE_FIELD (type, i)) && TYPE_FIELD_PACKED (type, i)) @@ -912,7 +726,7 @@ pascal_object_print_value (struct type *type, const gdb_byte *valaddr, { int boffset = 0; struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); - char *basename = type_name_no_tag (baseclass); + const char *basename = type_name_no_tag (baseclass); const gdb_byte *base_valaddr = NULL; int thisoffset; volatile struct gdb_exception ex; @@ -953,8 +767,11 @@ pascal_object_print_value (struct type *type, const gdb_byte *valaddr, if (boffset < 0 || boffset >= TYPE_LENGTH (type)) { - /* FIXME (alloc): not safe is baseclass is really really big. */ - gdb_byte *buf = alloca (TYPE_LENGTH (baseclass)); + gdb_byte *buf; + struct cleanup *back_to; + + buf = xmalloc (TYPE_LENGTH (baseclass)); + back_to = make_cleanup (xfree, buf); base_valaddr = buf; if (target_read_memory (address + boffset, buf, @@ -963,6 +780,7 @@ pascal_object_print_value (struct type *type, const gdb_byte *valaddr, address = address + boffset; thisoffset = 0; boffset = 0; + do_cleanups (back_to); } else base_valaddr = valaddr; diff --git a/contrib/gdb-7/gdb/parse.c b/contrib/gdb-7/gdb/parse.c index b0fa2379fd..4c84b2bc7a 100644 --- a/contrib/gdb-7/gdb/parse.c +++ b/contrib/gdb-7/gdb/parse.c @@ -1,7 +1,6 @@ /* Parse expressions for GDB. - Copyright (C) 1986, 1989-2001, 2004-2005, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. Modified from expread.y by the Department of Computer Science at the State University of New York at Buffalo, 1991. @@ -71,37 +70,32 @@ const struct exp_descriptor exp_descriptor_standard = struct expression *expout; int expout_size; int expout_ptr; -struct block *expression_context_block; +const struct block *expression_context_block; CORE_ADDR expression_context_pc; -struct block *innermost_block; +const struct block *innermost_block; int arglist_len; -union type_stack_elt *type_stack; -int type_stack_depth, type_stack_size; +static struct type_stack type_stack; char *lexptr; char *prev_lexptr; int paren_depth; int comma_terminates; -/* True if parsing an expression to find a field reference. This is - only used by completion. */ -int in_parse_field; +/* True if parsing an expression to attempt completion. */ +int parse_completion; /* The index of the last struct expression directly before a '.' or '->'. This is set when parsing and is only used when completing a field name. It is -1 if no dereference operation was found. */ static int expout_last_struct = -1; -/* A temporary buffer for identifiers, so we can null-terminate them. +/* If we are completing a tagged type name, this will be nonzero. */ +static enum type_code expout_tag_completion_type = TYPE_CODE_UNDEF; + +/* The token for tagged type name completion. */ +static char *expout_completion_name; - We allocate this with xrealloc. parse_exp_1 used to allocate with - alloca, using the size of the whole expression as a conservative - estimate of the space needed. However, macro expansion can - introduce names longer than the original expression; there's no - practical way to know beforehand how large that might be. */ -char *namecopy; -size_t namecopy_size; -static int expressiondebug = 0; +static unsigned int expressiondebug = 0; static void show_expressiondebug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -123,12 +117,11 @@ show_parserdebug (struct ui_file *file, int from_tty, static void free_funcalls (void *ignore); -static int prefixify_expression (struct expression *); - static int prefixify_subexp (struct expression *, struct expression *, int, int); -static struct expression *parse_exp_in_context (char **, struct block *, int, +static struct expression *parse_exp_in_context (char **, CORE_ADDR, + const struct block *, int, int, int *); void _initialize_parse (void); @@ -192,6 +185,35 @@ free_funcalls (void *ignore) /* This page contains the functions for adding data to the struct expression being constructed. */ +/* See definition in parser-defs.h. */ + +void +initialize_expout (int initial_size, const struct language_defn *lang, + struct gdbarch *gdbarch) +{ + expout_size = initial_size; + expout_ptr = 0; + expout = xmalloc (sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_size)); + expout->language_defn = lang; + expout->gdbarch = gdbarch; +} + +/* See definition in parser-defs.h. */ + +void +reallocate_expout (void) +{ + /* Record the actual number of expression elements, and then + reallocate the expression memory so that we free up any + excess elements. */ + + expout->nelts = expout_ptr; + expout = xrealloc ((char *) expout, + sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_ptr)); +} + /* Add one element to the end of the expression. */ /* To avoid a bug in the Sun 4 compiler, we pass things that can fit into @@ -231,7 +253,7 @@ write_exp_elt_sym (struct symbol *expelt) } void -write_exp_elt_block (struct block *b) +write_exp_elt_block (const struct block *b) { union exp_element tmp; @@ -562,9 +584,32 @@ write_exp_msymbol (struct minimal_symbol *msymbol) void mark_struct_expression (void) { + gdb_assert (parse_completion + && expout_tag_completion_type == TYPE_CODE_UNDEF); expout_last_struct = expout_ptr; } +/* Indicate that the current parser invocation is completing a tag. + TAG is the type code of the tag, and PTR and LENGTH represent the + start of the tag name. */ + +void +mark_completion_tag (enum type_code tag, const char *ptr, int length) +{ + gdb_assert (parse_completion + && expout_tag_completion_type == TYPE_CODE_UNDEF + && expout_completion_name == NULL + && expout_last_struct == -1); + gdb_assert (tag == TYPE_CODE_UNION + || tag == TYPE_CODE_STRUCT + || tag == TYPE_CODE_CLASS + || tag == TYPE_CODE_ENUM); + expout_tag_completion_type = tag; + expout_completion_name = xmalloc (length + 1); + memcpy (expout_completion_name, ptr, length); + expout_completion_name[length] = '\0'; +} + /* Recognize tokens that start with '$'. These include: @@ -646,7 +691,7 @@ write_dollar_variable (struct stoken str) have names beginning with $ or $$. Check for those, first. */ sym = lookup_symbol (copy_name (str), (struct block *) NULL, - VAR_DOMAIN, (int *) NULL); + VAR_DOMAIN, NULL); if (sym) { write_exp_elt_opcode (OP_VAR_VALUE); @@ -744,13 +789,28 @@ find_template_name_end (char *p) } +/* Return a null-terminated temporary copy of the name of a string token. + + Tokens that refer to names do so with explicit pointer and length, + so they can share the storage that lexptr is parsing. + When it is necessary to pass a name to a function that expects + a null-terminated string, the substring is copied out + into a separate block of storage. -/* Return a null-terminated temporary copy of the name - of a string token. */ + N.B. A single buffer is reused on each call. */ char * copy_name (struct stoken token) { + /* A temporary buffer for identifiers, so we can null-terminate them. + We allocate this with xrealloc. parse_exp_1 used to allocate with + alloca, using the size of the whole expression as a conservative + estimate of the space needed. However, macro expansion can + introduce names longer than the original expression; there's no + practical way to know beforehand how large that might be. */ + static char *namecopy; + static size_t namecopy_size; + /* Make sure there's enough space for the token. */ if (namecopy_size < token.length + 1) { @@ -764,14 +824,10 @@ copy_name (struct stoken token) return namecopy; } -/* Reverse an expression from suffix form (in which it is constructed) - to prefix form (in which we can conveniently print or execute it). - Ordinarily this always returns -1. However, if EXPOUT_LAST_STRUCT - is not -1 (i.e., we are trying to complete a field name), it will - return the index of the subexpression which is the left-hand-side - of the struct operation at EXPOUT_LAST_STRUCT. */ -static int +/* See comments on parser-defs.h. */ + +int prefixify_expression (struct expression *expr) { int len = sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts); @@ -882,10 +938,16 @@ operator_length_standard (const struct expression *expr, int endpos, oplen = 3; break; - case BINOP_VAL: - case UNOP_CAST: + case UNOP_CAST_TYPE: case UNOP_DYNAMIC_CAST: case UNOP_REINTERPRET_CAST: + case UNOP_MEMVAL_TYPE: + oplen = 1; + args = 2; + break; + + case BINOP_VAL: + case UNOP_CAST: case UNOP_MEMVAL: oplen = 3; args = 1; @@ -904,6 +966,8 @@ operator_length_standard (const struct expression *expr, int endpos, case UNOP_ODD: case UNOP_ORD: case UNOP_TRUNC: + case OP_TYPEOF: + case OP_DECLTYPE: oplen = 1; args = 1; break; @@ -915,7 +979,6 @@ operator_length_standard (const struct expression *expr, int endpos, oplen++; break; - case OP_LABELED: case STRUCTOP_STRUCT: case STRUCTOP_PTR: args = 1; @@ -931,12 +994,6 @@ operator_length_standard (const struct expression *expr, int endpos, oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1); break; - case OP_BITSTRING: - oplen = longest_to_int (expr->elts[endpos - 2].longconst); - oplen = (oplen + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT; - oplen = 4 + BYTES_TO_EXP_ELEM (oplen); - break; - case OP_ARRAY: oplen = 4; args = longest_to_int (expr->elts[endpos - 2].longconst); @@ -946,7 +1003,6 @@ operator_length_standard (const struct expression *expr, int endpos, case TERNOP_COND: case TERNOP_SLICE: - case TERNOP_SLICE_COUNT: args = 3; break; @@ -1069,9 +1125,18 @@ prefixify_subexp (struct expression *inexpr, If COMMA is nonzero, stop if a comma is reached. */ struct expression * -parse_exp_1 (char **stringptr, struct block *block, int comma) +parse_exp_1 (const char **stringptr, CORE_ADDR pc, const struct block *block, + int comma) { - return parse_exp_in_context (stringptr, block, comma, 0, NULL); + struct expression *expr; + char *const_hack = *stringptr ? xstrdup (*stringptr) : NULL; + char *orig = const_hack; + struct cleanup *back_to = make_cleanup (xfree, const_hack); + + expr = parse_exp_in_context (&const_hack, pc, block, comma, 0, NULL); + (*stringptr) += const_hack - orig; + do_cleanups (back_to); + return expr; } /* As for parse_exp_1, except that if VOID_CONTEXT_P, then @@ -1082,11 +1147,11 @@ parse_exp_1 (char **stringptr, struct block *block, int comma) is left untouched. */ static struct expression * -parse_exp_in_context (char **stringptr, struct block *block, int comma, - int void_context_p, int *out_subexp) +parse_exp_in_context (char **stringptr, CORE_ADDR pc, const struct block *block, + int comma, int void_context_p, int *out_subexp) { volatile struct gdb_exception except; - struct cleanup *old_chain; + struct cleanup *old_chain, *inner_chain; const struct language_defn *lang = NULL; int subexp; @@ -1094,8 +1159,11 @@ parse_exp_in_context (char **stringptr, struct block *block, int comma, prev_lexptr = NULL; paren_depth = 0; - type_stack_depth = 0; + type_stack.depth = 0; expout_last_struct = -1; + expout_tag_completion_type = TYPE_CODE_UNDEF; + xfree (expout_completion_name); + expout_completion_name = NULL; comma_terminates = comma; @@ -1110,8 +1178,10 @@ parse_exp_in_context (char **stringptr, struct block *block, int comma, /* If no context specified, try using the current frame, if any. */ if (!expression_context_block) expression_context_block = get_selected_block (&expression_context_pc); - else + else if (pc == 0) expression_context_pc = BLOCK_START (expression_context_block); + else + expression_context_pc = pc; /* Fall back to using the current source static context, if any. */ @@ -1151,12 +1221,13 @@ parse_exp_in_context (char **stringptr, struct block *block, int comma, else lang = current_language; - expout_size = 10; - expout_ptr = 0; - expout = (struct expression *) - xmalloc (sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_size)); - expout->language_defn = lang; - expout->gdbarch = get_current_arch (); + /* get_current_arch may reset CURRENT_LANGUAGE via select_frame. + While we need CURRENT_LANGUAGE to be set to LANG (for lookup_symbol + and others called from *.y) ensure CURRENT_LANGUAGE gets restored + to the value matching SELECTED_FRAME as set by get_current_arch. */ + initialize_expout (10, lang, get_current_arch ()); + inner_chain = make_cleanup_restore_current_language (); + set_language (lang->la_language); TRY_CATCH (except, RETURN_MASK_ALL) { @@ -1165,23 +1236,14 @@ parse_exp_in_context (char **stringptr, struct block *block, int comma, } if (except.reason < 0) { - if (! in_parse_field) + if (! parse_completion) { xfree (expout); throw_exception (except); } } - discard_cleanups (old_chain); - - /* Record the actual number of expression elements, and then - reallocate the expression memory so that we free up any - excess elements. */ - - expout->nelts = expout_ptr; - expout = (struct expression *) - xrealloc ((char *) expout, - sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_ptr)); + reallocate_expout (); /* Convert expression from postfix form as generated by yacc parser, to a prefix form. */ @@ -1199,6 +1261,9 @@ parse_exp_in_context (char **stringptr, struct block *block, int comma, if (expressiondebug) dump_prefix_expression (expout, gdb_stdlog); + do_cleanups (inner_chain); + discard_cleanups (old_chain); + *stringptr = lexptr; return expout; } @@ -1207,11 +1272,11 @@ parse_exp_in_context (char **stringptr, struct block *block, int comma, to use up all of the contents of STRING. */ struct expression * -parse_expression (char *string) +parse_expression (const char *string) { struct expression *exp; - exp = parse_exp_1 (&string, 0, 0); + exp = parse_exp_1 (&string, 0, 0, 0); if (*string) error (_("Junk after end of expression.")); return exp; @@ -1226,7 +1291,8 @@ parse_expression (char *string) *NAME must be freed by the caller. */ struct type * -parse_field_expression (char *string, char **name) +parse_expression_for_completion (char *string, char **name, + enum type_code *code) { struct expression *exp = NULL; struct value *val; @@ -1235,12 +1301,21 @@ parse_field_expression (char *string, char **name) TRY_CATCH (except, RETURN_MASK_ERROR) { - in_parse_field = 1; - exp = parse_exp_in_context (&string, 0, 0, 0, &subexp); + parse_completion = 1; + exp = parse_exp_in_context (&string, 0, 0, 0, 0, &subexp); } - in_parse_field = 0; + parse_completion = 0; if (except.reason < 0 || ! exp) return NULL; + + if (expout_tag_completion_type != TYPE_CODE_UNDEF) + { + *code = expout_tag_completion_type; + *name = expout_completion_name; + expout_completion_name = NULL; + return NULL; + } + if (expout_last_struct == -1) { xfree (exp); @@ -1282,7 +1357,6 @@ int parse_float (const char *p, int len, DOUBLEST *d, const char **suffix) { char *copy; - char *s; int n, num; copy = xmalloc (len + 1); @@ -1341,54 +1415,214 @@ parse_c_float (struct gdbarch *gdbarch, const char *p, int len, /* Stuff for maintaining a stack of types. Currently just used by C, but probably useful for any language which declares its types "backwards". */ +/* Ensure that there are HOWMUCH open slots on the type stack STACK. */ + static void -check_type_stack_depth (void) +type_stack_reserve (struct type_stack *stack, int howmuch) { - if (type_stack_depth == type_stack_size) + if (stack->depth + howmuch >= stack->size) { - type_stack_size *= 2; - type_stack = (union type_stack_elt *) - xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack)); + stack->size *= 2; + if (stack->size < howmuch) + stack->size = howmuch; + stack->elements = xrealloc (stack->elements, + stack->size * sizeof (union type_stack_elt)); } } +/* Ensure that there is a single open slot in the global type stack. */ + +static void +check_type_stack_depth (void) +{ + type_stack_reserve (&type_stack, 1); +} + +/* A helper function for insert_type and insert_type_address_space. + This does work of expanding the type stack and inserting the new + element, ELEMENT, into the stack at location SLOT. */ + +static void +insert_into_type_stack (int slot, union type_stack_elt element) +{ + check_type_stack_depth (); + + if (slot < type_stack.depth) + memmove (&type_stack.elements[slot + 1], &type_stack.elements[slot], + (type_stack.depth - slot) * sizeof (union type_stack_elt)); + type_stack.elements[slot] = element; + ++type_stack.depth; +} + +/* Insert a new type, TP, at the bottom of the type stack. If TP is + tp_pointer or tp_reference, it is inserted at the bottom. If TP is + a qualifier, it is inserted at slot 1 (just above a previous + tp_pointer) if there is anything on the stack, or simply pushed if + the stack is empty. Other values for TP are invalid. */ + +void +insert_type (enum type_pieces tp) +{ + union type_stack_elt element; + int slot; + + gdb_assert (tp == tp_pointer || tp == tp_reference + || tp == tp_const || tp == tp_volatile); + + /* If there is anything on the stack (we know it will be a + tp_pointer), insert the qualifier above it. Otherwise, simply + push this on the top of the stack. */ + if (type_stack.depth && (tp == tp_const || tp == tp_volatile)) + slot = 1; + else + slot = 0; + + element.piece = tp; + insert_into_type_stack (slot, element); +} + void push_type (enum type_pieces tp) { check_type_stack_depth (); - type_stack[type_stack_depth++].piece = tp; + type_stack.elements[type_stack.depth++].piece = tp; } void push_type_int (int n) { check_type_stack_depth (); - type_stack[type_stack_depth++].int_val = n; + type_stack.elements[type_stack.depth++].int_val = n; } +/* Insert a tp_space_identifier and the corresponding address space + value into the stack. STRING is the name of an address space, as + recognized by address_space_name_to_int. If the stack is empty, + the new elements are simply pushed. If the stack is not empty, + this function assumes that the first item on the stack is a + tp_pointer, and the new values are inserted above the first + item. */ + void -push_type_address_space (char *string) +insert_type_address_space (char *string) { - push_type_int (address_space_name_to_int (parse_gdbarch, string)); + union type_stack_elt element; + int slot; + + /* If there is anything on the stack (we know it will be a + tp_pointer), insert the address space qualifier above it. + Otherwise, simply push this on the top of the stack. */ + if (type_stack.depth) + slot = 1; + else + slot = 0; + + element.piece = tp_space_identifier; + insert_into_type_stack (slot, element); + element.int_val = address_space_name_to_int (parse_gdbarch, string); + insert_into_type_stack (slot, element); } enum type_pieces pop_type (void) { - if (type_stack_depth) - return type_stack[--type_stack_depth].piece; + if (type_stack.depth) + return type_stack.elements[--type_stack.depth].piece; return tp_end; } int pop_type_int (void) { - if (type_stack_depth) - return type_stack[--type_stack_depth].int_val; + if (type_stack.depth) + return type_stack.elements[--type_stack.depth].int_val; /* "Can't happen". */ return 0; } +/* Pop a type list element from the global type stack. */ + +static VEC (type_ptr) * +pop_typelist (void) +{ + gdb_assert (type_stack.depth); + return type_stack.elements[--type_stack.depth].typelist_val; +} + +/* Pop a type_stack element from the global type stack. */ + +static struct type_stack * +pop_type_stack (void) +{ + gdb_assert (type_stack.depth); + return type_stack.elements[--type_stack.depth].stack_val; +} + +/* Append the elements of the type stack FROM to the type stack TO. + Always returns TO. */ + +struct type_stack * +append_type_stack (struct type_stack *to, struct type_stack *from) +{ + type_stack_reserve (to, from->depth); + + memcpy (&to->elements[to->depth], &from->elements[0], + from->depth * sizeof (union type_stack_elt)); + to->depth += from->depth; + + return to; +} + +/* Push the type stack STACK as an element on the global type stack. */ + +void +push_type_stack (struct type_stack *stack) +{ + check_type_stack_depth (); + type_stack.elements[type_stack.depth++].stack_val = stack; + push_type (tp_type_stack); +} + +/* Copy the global type stack into a newly allocated type stack and + return it. The global stack is cleared. The returned type stack + must be freed with type_stack_cleanup. */ + +struct type_stack * +get_type_stack (void) +{ + struct type_stack *result = XNEW (struct type_stack); + + *result = type_stack; + type_stack.depth = 0; + type_stack.size = 0; + type_stack.elements = NULL; + + return result; +} + +/* A cleanup function that destroys a single type stack. */ + +void +type_stack_cleanup (void *arg) +{ + struct type_stack *stack = arg; + + xfree (stack->elements); + xfree (stack); +} + +/* Push a function type with arguments onto the global type stack. + LIST holds the argument types. If the final item in LIST is NULL, + then the function will be varargs. */ + +void +push_typelist (VEC (type_ptr) *list) +{ + check_type_stack_depth (); + type_stack.elements[type_stack.depth++].typelist_val = list; + push_type (tp_function_with_arguments); +} + /* Pop the type stack and return the type which corresponds to FOLLOW_TYPE as modified by all the stuff on the stack. */ struct type * @@ -1475,6 +1709,36 @@ follow_types (struct type *follow_type) done with it. */ follow_type = lookup_function_type (follow_type); break; + + case tp_function_with_arguments: + { + VEC (type_ptr) *args = pop_typelist (); + + follow_type + = lookup_function_type_with_arguments (follow_type, + VEC_length (type_ptr, args), + VEC_address (type_ptr, + args)); + VEC_free (type_ptr, args); + } + break; + + case tp_type_stack: + { + struct type_stack *stack = pop_type_stack (); + /* Sort of ugly, but not really much worse than the + alternatives. */ + struct type_stack save = type_stack; + + type_stack = *stack; + follow_type = follow_types (follow_type); + gdb_assert (type_stack.depth == 0); + + type_stack = save; + } + break; + default: + gdb_assert_not_reached ("unrecognized tp_ value in follow_types"); } return follow_type; } @@ -1525,8 +1789,6 @@ operator_check_standard (struct expression *exp, int pos, case OP_SCOPE: case OP_TYPE: case UNOP_CAST: - case UNOP_DYNAMIC_CAST: - case UNOP_REINTERPRET_CAST: case UNOP_MAX: case UNOP_MEMVAL: case UNOP_MIN: @@ -1642,20 +1904,19 @@ exp_uses_objfile (struct expression *exp, struct objfile *objfile) void _initialize_parse (void) { - type_stack_size = 80; - type_stack_depth = 0; - type_stack = (union type_stack_elt *) - xmalloc (type_stack_size * sizeof (*type_stack)); - - add_setshow_zinteger_cmd ("expression", class_maintenance, - &expressiondebug, - _("Set expression debugging."), - _("Show expression debugging."), - _("When non-zero, the internal representation " - "of expressions will be printed."), - NULL, - show_expressiondebug, - &setdebuglist, &showdebuglist); + type_stack.size = 0; + type_stack.depth = 0; + type_stack.elements = NULL; + + add_setshow_zuinteger_cmd ("expression", class_maintenance, + &expressiondebug, + _("Set expression debugging."), + _("Show expression debugging."), + _("When non-zero, the internal representation " + "of expressions will be printed."), + NULL, + show_expressiondebug, + &setdebuglist, &showdebuglist); add_setshow_boolean_cmd ("parser", class_maintenance, &parser_debug, _("Set parser debugging."), diff --git a/contrib/gdb-7/gdb/parser-defs.h b/contrib/gdb-7/gdb/parser-defs.h index d14aea6bbe..8d25311d27 100644 --- a/contrib/gdb-7/gdb/parser-defs.h +++ b/contrib/gdb-7/gdb/parser-defs.h @@ -1,7 +1,6 @@ /* Parser definitions for GDB. - Copyright (C) 1986, 1989-2000, 2002, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. Modified from expread.y by the Department of Computer Science at the State University of New York at Buffalo. @@ -25,6 +24,7 @@ #define PARSER_DEFS_H 1 #include "doublest.h" +#include "vec.h" struct block; @@ -40,7 +40,7 @@ extern int expout_ptr; /* If this is nonzero, this block is used as the lexical context for symbol names. */ -extern struct block *expression_context_block; +extern const struct block *expression_context_block; /* If expression_context_block is non-zero, then this is the PC within the block that we want to evaluate expressions at. When debugging @@ -50,12 +50,12 @@ extern CORE_ADDR expression_context_pc; /* The innermost context required by the stack and register variables we've encountered so far. */ -extern struct block *innermost_block; +extern const struct block *innermost_block; /* The block in which the most recently discovered symbol was found. FIXME: Should be declared along with lookup_symbol in symtab.h; is not related specifically to parsing. */ -extern struct block *block_found; +extern const struct block *block_found; /* Number of arguments seen so far in innermost function call. */ extern int arglist_len; @@ -107,6 +107,8 @@ struct objc_class_str int class; }; +typedef struct type *type_ptr; +DEF_VEC_P (type_ptr); /* For parsing of complicated types. An array should be preceded in the list by the size of the array. */ @@ -116,19 +118,57 @@ enum type_pieces tp_pointer, tp_reference, tp_array, - tp_function, + tp_function, + tp_function_with_arguments, tp_const, tp_volatile, - tp_space_identifier + tp_space_identifier, + tp_type_stack }; /* The stack can contain either an enum type_pieces or an int. */ union type_stack_elt { enum type_pieces piece; int int_val; + struct type_stack *stack_val; + VEC (type_ptr) *typelist_val; }; -extern union type_stack_elt *type_stack; -extern int type_stack_depth, type_stack_size; + +/* The type stack is an instance of this structure. */ + +struct type_stack +{ + /* Elements on the stack. */ + union type_stack_elt *elements; + /* Current stack depth. */ + int depth; + /* Allocated size of stack. */ + int size; +}; + +/* Helper function to initialize the expout, expout_size, expout_ptr + trio before it is used to store expression elements created during + the parsing of an expression. INITIAL_SIZE is the initial size of + the expout array. LANG is the language used to parse the expression. + And GDBARCH is the gdbarch to use during parsing. */ + +extern void initialize_expout (int, const struct language_defn *, + struct gdbarch *); + +/* Helper function that frees any unsed space in the expout array. + It is generally used when the parser has just been parsed and + created. */ + +extern void reallocate_expout (void); + +/* Reverse an expression from suffix form (in which it is constructed) + to prefix form (in which we can conveniently print or execute it). + Ordinarily this always returns -1. However, if EXPOUT_LAST_STRUCT + is not -1 (i.e., we are trying to complete a field name), it will + return the index of the subexpression which is the left-hand-side + of the struct operation at EXPOUT_LAST_STRUCT. */ + +extern int prefixify_expression (struct expression *expr); extern void write_exp_elt_opcode (enum exp_opcode); @@ -150,7 +190,7 @@ 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 *); +extern void write_exp_elt_block (const struct block *); extern void write_exp_elt_objfile (struct objfile *objfile); @@ -168,16 +208,29 @@ extern int end_arglist (void); extern char *copy_name (struct stoken); +extern void insert_type (enum type_pieces); + extern void push_type (enum type_pieces); extern void push_type_int (int); -extern void push_type_address_space (char *); +extern void insert_type_address_space (char *); extern enum type_pieces pop_type (void); extern int pop_type_int (void); +extern struct type_stack *get_type_stack (void); + +extern struct type_stack *append_type_stack (struct type_stack *to, + struct type_stack *from); + +extern void push_type_stack (struct type_stack *stack); + +extern void type_stack_cleanup (void *arg); + +extern void push_typelist (VEC (type_ptr) *typelist); + extern int length_of_subexp (struct expression *, int); extern int dump_subexp (struct expression *, struct ui_file *, int); @@ -216,17 +269,6 @@ extern char *lexptr; Currently used only for error reporting. */ extern char *prev_lexptr; -/* Tokens that refer to names do so with explicit pointer and length, - so they can share the storage that lexptr is parsing. - - When it is necessary to pass a name to a function that expects - a null-terminated string, the substring is copied out - into a block of storage that namecopy points to. - - namecopy is allocated once, guaranteed big enough, for each parsing. */ - -extern char *namecopy; - /* Current depth in parentheses within the expression. */ extern int paren_depth; @@ -292,7 +334,10 @@ struct exp_descriptor void *data), void *data); - /* Name of this operator for dumping purposes. */ + /* Name of this operator for dumping purposes. + The returned value should never be NULL, even if EXP_OPCODE is + an unknown opcode (a string containing an image of the numeric + value of the opcode can be returned, for instance). */ char *(*op_name) (enum exp_opcode); /* Dump the rest of this (prefix) expression after the operator @@ -326,4 +371,8 @@ extern void parser_fprintf (FILE *, const char *, ...) ATTRIBUTE_PRINTF (2, 3); extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile); +extern void mark_completion_tag (enum type_code, const char *ptr, + int length); + #endif /* PARSER_DEFS_H */ + diff --git a/contrib/gdb-7/gdb/posix-hdep.c b/contrib/gdb-7/gdb/posix-hdep.c index 793f1c60d3..3280f1cac1 100644 --- a/contrib/gdb-7/gdb/posix-hdep.c +++ b/contrib/gdb-7/gdb/posix-hdep.c @@ -1,6 +1,6 @@ /* Host support routines for MinGW, for GDB, the GNU debugger. - Copyright (C) 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2006-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/ppc-ravenscar-thread.c b/contrib/gdb-7/gdb/ppc-ravenscar-thread.c new file mode 100644 index 0000000000..1993fceda7 --- /dev/null +++ b/contrib/gdb-7/gdb/ppc-ravenscar-thread.c @@ -0,0 +1,291 @@ +/* Ravenscar PowerPC target support. + + Copyright (C) 2011-2013 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 "gdbcore.h" +#include "regcache.h" +#include "ppc-tdep.h" +#include "inferior.h" +#include "ravenscar-thread.h" +#include "ppc-ravenscar-thread.h" + +#define NO_OFFSET -1 + +/* See ppc-tdep.h for register numbers. */ + +static const int powerpc_context_offsets[] = +{ + /* R0 - R32 */ + NO_OFFSET, 0, 4, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, 8, 12, 16, + 20, 24, 28, 32, + 36, 40, 44, 48, + 52, 56, 60, 64, + 68, 72, 76, 80, + + /* F0 - F31 */ + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, 96, 104, + 112, 120, 128, 136, + 144, 152, 160, 168, + 176, 184, 192, 200, + 208, 216, 224, 232, + + /* PC, MSR, CR, LR */ + 88, NO_OFFSET, 84, NO_OFFSET, + + /* CTR, XER, FPSCR */ + NO_OFFSET, NO_OFFSET, 240 +}; + +static const int e500_context_offsets[] = +{ + /* R0 - R32 */ + NO_OFFSET, 4, 12, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, 20, 28, 36, + 44, 52, 60, 68, + 76, 84, 92, 100, + 108, 116, 124, 132, + 140, 148, 156, 164, + + /* F0 - F31 */ + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + + /* PC, MSR, CR, LR */ + 172, NO_OFFSET, 168, NO_OFFSET, + + /* CTR, XER, FPSCR, MQ */ + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + + /* Upper R0-R32. */ + NO_OFFSET, 0, 8, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET, + NO_OFFSET, 16, 24, 32, + 40, 48, 56, 64, + 72, 80, 88, 96, + 104, 112, 120, 128, + 136, 144, 152, 160, + + /* ACC, FSCR */ + NO_OFFSET, 176 +}; + +/* The register layout info. */ + +struct ravenscar_reg_info +{ + /* A table providing the offset relative to the context structure + where each register is saved. */ + const int *context_offsets; + + /* The number of elements in the context_offsets table above. */ + int context_offsets_size; +}; + +/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the + regcache. */ + +static void +supply_register_at_address (struct regcache *regcache, int regnum, + CORE_ADDR register_addr) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + int buf_size = register_size (gdbarch, regnum); + char *buf; + + buf = (char *) alloca (buf_size); + read_memory (register_addr, buf, buf_size); + regcache_raw_supply (regcache, regnum, buf); +} + +/* Return true if, for a non-running thread, REGNUM has been saved on the + Thread_Descriptor. */ + +static int +register_in_thread_descriptor_p (const struct ravenscar_reg_info *reg_info, + int regnum) +{ + return (regnum < reg_info->context_offsets_size + && reg_info->context_offsets[regnum] != NO_OFFSET); +} + +/* to_fetch_registers when inferior_ptid is different from the running + thread. */ + +static void +ppc_ravenscar_generic_fetch_registers + (const struct ravenscar_reg_info *reg_info, + struct regcache *regcache, int regnum) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + const int sp_regnum = gdbarch_sp_regnum (gdbarch); + const int num_regs = gdbarch_num_regs (gdbarch); + int current_regnum; + CORE_ADDR current_address; + CORE_ADDR thread_descriptor_address; + + /* The tid is the thread_id field, which is a pointer to the thread. */ + thread_descriptor_address = (CORE_ADDR) ptid_get_tid (inferior_ptid); + + /* Read registers. */ + for (current_regnum = 0; current_regnum < num_regs; current_regnum++) + { + if (register_in_thread_descriptor_p (reg_info, current_regnum)) + { + current_address = thread_descriptor_address + + reg_info->context_offsets[current_regnum]; + supply_register_at_address (regcache, current_regnum, + current_address); + } + } +} + +/* to_prepare_to_store when inferior_ptid is different from the running + thread. */ + +static void +ppc_ravenscar_generic_prepare_to_store (struct regcache *regcache) +{ + /* Nothing to do. */ +} + +/* to_store_registers when inferior_ptid is different from the running + thread. */ + +static void +ppc_ravenscar_generic_store_registers + (const struct ravenscar_reg_info *reg_info, + struct regcache *regcache, int regnum) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + int buf_size = register_size (gdbarch, regnum); + char buf [buf_size]; + ULONGEST register_address; + + if (register_in_thread_descriptor_p (reg_info, regnum)) + register_address + = ptid_get_tid (inferior_ptid) + reg_info->context_offsets [regnum]; + else + return; + + regcache_raw_collect (regcache, regnum, buf); + write_memory (register_address, + buf, + buf_size); +} + +/* The ravenscar_reg_info for most PowerPC targets. */ + +static const struct ravenscar_reg_info ppc_reg_info = +{ + powerpc_context_offsets, + ARRAY_SIZE (powerpc_context_offsets), +}; + +/* Implement the to_fetch_registers ravenscar_arch_ops method + for most PowerPC targets. */ + +static void +ppc_ravenscar_powerpc_fetch_registers (struct regcache *regcache, int regnum) +{ + ppc_ravenscar_generic_fetch_registers (&ppc_reg_info, regcache, regnum); +} + +/* Implement the to_store_registers ravenscar_arch_ops method + for most PowerPC targets. */ + +static void +ppc_ravenscar_powerpc_store_registers (struct regcache *regcache, int regnum) +{ + ppc_ravenscar_generic_store_registers (&ppc_reg_info, regcache, regnum); +} + +/* The ravenscar_arch_ops vector for most PowerPC targets. */ + +static struct ravenscar_arch_ops ppc_ravenscar_powerpc_ops = +{ + ppc_ravenscar_powerpc_fetch_registers, + ppc_ravenscar_powerpc_store_registers, + ppc_ravenscar_generic_prepare_to_store +}; + +/* Register ppc_ravenscar_powerpc_ops in GDBARCH. */ + +void +register_ppc_ravenscar_ops (struct gdbarch *gdbarch) +{ + set_gdbarch_ravenscar_ops (gdbarch, &ppc_ravenscar_powerpc_ops); +} + +/* The ravenscar_reg_info for E500 targets. */ + +static const struct ravenscar_reg_info e500_reg_info = +{ + e500_context_offsets, + ARRAY_SIZE (e500_context_offsets), +}; + +/* Implement the to_fetch_registers ravenscar_arch_ops method + for E500 targets. */ + +static void +ppc_ravenscar_e500_fetch_registers (struct regcache *regcache, int regnum) +{ + ppc_ravenscar_generic_fetch_registers (&e500_reg_info, regcache, regnum); +} + +/* Implement the to_store_registers ravenscar_arch_ops method + for E500 targets. */ + +static void +ppc_ravenscar_e500_store_registers (struct regcache *regcache, int regnum) +{ + ppc_ravenscar_generic_store_registers (&e500_reg_info, regcache, regnum); +} + +/* The ravenscar_arch_ops vector for E500 targets. */ + +static struct ravenscar_arch_ops ppc_ravenscar_e500_ops = +{ + ppc_ravenscar_e500_fetch_registers, + ppc_ravenscar_e500_store_registers, + ppc_ravenscar_generic_prepare_to_store +}; + +/* Register ppc_ravenscar_e500_ops in GDBARCH. */ + +void +register_e500_ravenscar_ops (struct gdbarch *gdbarch) +{ + set_gdbarch_ravenscar_ops (gdbarch, &ppc_ravenscar_e500_ops); +} diff --git a/contrib/gdb-7/gdb/common/xml-utils.h b/contrib/gdb-7/gdb/ppc-ravenscar-thread.h similarity index 69% copy from contrib/gdb-7/gdb/common/xml-utils.h copy to contrib/gdb-7/gdb/ppc-ravenscar-thread.h index 8d38ea1cb1..4acc937ca3 100644 --- a/contrib/gdb-7/gdb/common/xml-utils.h +++ b/contrib/gdb-7/gdb/ppc-ravenscar-thread.h @@ -1,6 +1,6 @@ -/* Shared helper routines for manipulating XML. +/* Ravenscar PowerPC target support. - Copyright (C) 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2012-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,12 +17,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef XML_UTILS_H -#define XML_UTILS_H +#ifndef PPC_RAVENSCAR_THREAD_H +#define PPC_RAVENSCAR_THREAD_H -/* Return a malloc allocated string with special characters from TEXT - replaced by entity references. */ +struct gdbarch; -extern char *xml_escape_text (const char *text); +extern void register_ppc_ravenscar_ops (struct gdbarch *gdbarch); + +extern void register_e500_ravenscar_ops (struct gdbarch *gdbarch); #endif diff --git a/contrib/gdb-7/gdb/printcmd.c b/contrib/gdb-7/gdb/printcmd.c index bee8a85090..695c180c26 100644 --- a/contrib/gdb-7/gdb/printcmd.c +++ b/contrib/gdb-7/gdb/printcmd.c @@ -1,6 +1,6 @@ /* Print values for GNU debugger GDB. - Copyright (C) 1986-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -49,18 +49,13 @@ #include "charset.h" #include "arch-utils.h" #include "cli/cli-utils.h" +#include "format.h" +#include "source.h" #ifdef TUI #include "tui/tui.h" /* For tui_active et al. */ #endif -#if defined(__MINGW32__) && !defined(PRINTF_HAS_LONG_LONG) -# define USE_PRINTF_I64 1 -# define PRINTF_HAS_LONG_LONG -#else -# define USE_PRINTF_I64 0 -#endif - struct format_data { int count; @@ -128,7 +123,7 @@ show_print_symbol_filename (struct ui_file *file, int from_tty, So that we can disable it if we get a signal within it. -1 when not doing one. */ -int current_display_number; +static int current_display_number; struct display { @@ -151,7 +146,7 @@ struct display struct program_space *pspace; /* Innermost block required by this expression when evaluated. */ - struct block *block; + const struct block *block; /* Status of this display (enabled or disabled). */ int enabled_p; @@ -178,8 +173,6 @@ static int display_number; /* Prototypes for exported functions. */ -void output_command (char *, int); - void _initialize_printcmd (void); /* Prototypes for local functions. */ @@ -352,13 +345,12 @@ float_type_from_length (struct type *type) { struct gdbarch *gdbarch = get_type_arch (type); const struct builtin_type *builtin = builtin_type (gdbarch); - unsigned int len = TYPE_LENGTH (type); - if (len == TYPE_LENGTH (builtin->builtin_float)) + if (TYPE_LENGTH (type) == TYPE_LENGTH (builtin->builtin_float)) type = builtin->builtin_float; - else if (len == TYPE_LENGTH (builtin->builtin_double)) + else if (TYPE_LENGTH (type) == TYPE_LENGTH (builtin->builtin_double)) type = builtin->builtin_double; - else if (len == TYPE_LENGTH (builtin->builtin_long_double)) + else if (TYPE_LENGTH (type) == TYPE_LENGTH (builtin->builtin_long_double)) type = builtin->builtin_long_double; return type; @@ -568,9 +560,10 @@ set_next_address (struct gdbarch *gdbarch, CORE_ADDR addr) DO_DEMANGLE controls whether to print a symbol in its native "raw" form, or to interpret it as a possible C++ name and convert it back to source form. However note that DO_DEMANGLE can be overridden by the specific - settings of the demangle and asm_demangle variables. */ + settings of the demangle and asm_demangle variables. Returns + non-zero if anything was printed; zero otherwise. */ -void +int print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr, struct ui_file *stream, int do_demangle, char *leadin) @@ -589,7 +582,7 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr, &filename, &line, &unmapped)) { do_cleanups (cleanup_chain); - return; + return 0; } fputs_filtered (leadin, stream); @@ -616,6 +609,7 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr, fputs_filtered (">", stream); do_cleanups (cleanup_chain); + return 1; } /* Given an address ADDR return all the elements needed to print the @@ -638,7 +632,7 @@ build_address_symbolic (struct gdbarch *gdbarch, struct symbol *symbol; CORE_ADDR name_location = 0; struct obj_section *section = NULL; - char *name_temp = ""; + const char *name_temp = ""; /* Let's say it is mapped (not unmapped). */ *unmapped = 0; @@ -683,6 +677,14 @@ build_address_symbolic (struct gdbarch *gdbarch, name_temp = SYMBOL_LINKAGE_NAME (symbol); } + if (msymbol != NULL + && MSYMBOL_HAS_SIZE (msymbol) + && MSYMBOL_SIZE (msymbol) == 0 + && MSYMBOL_TYPE (msymbol) != mst_text + && MSYMBOL_TYPE (msymbol) != mst_text_gnu_ifunc + && MSYMBOL_TYPE (msymbol) != mst_file_text) + msymbol = NULL; + if (msymbol != NULL) { if (SYMBOL_VALUE_ADDRESS (msymbol) > name_location || symbol == NULL) @@ -723,7 +725,7 @@ build_address_symbolic (struct gdbarch *gdbarch, if (sal.symtab) { - *filename = xstrdup (sal.symtab->filename); + *filename = xstrdup (symtab_to_filename_for_display (sal.symtab)); *line = sal.line; } } @@ -763,29 +765,23 @@ pc_prefix (CORE_ADDR addr) /* Print address ADDR symbolically on STREAM. Parameter DEMANGLE controls whether to print the symbolic name "raw" or demangled. - Global setting "addressprint" controls whether to print hex address - or not. */ + Return non-zero if anything was printed; zero otherwise. */ -void -print_address_demangle (struct gdbarch *gdbarch, CORE_ADDR addr, +int +print_address_demangle (const struct value_print_options *opts, + struct gdbarch *gdbarch, CORE_ADDR addr, struct ui_file *stream, int do_demangle) { - struct value_print_options opts; - - get_user_print_options (&opts); - if (addr == 0) - { - fprintf_filtered (stream, "0"); - } - else if (opts.addressprint) + if (opts->addressprint) { fputs_filtered (paddress (gdbarch, addr), stream); print_address_symbolic (gdbarch, addr, stream, do_demangle, " "); } else { - print_address_symbolic (gdbarch, addr, stream, do_demangle, ""); + return print_address_symbolic (gdbarch, addr, stream, do_demangle, ""); } + return 1; } @@ -937,7 +933,7 @@ validate_format (struct format_data fmt, char *cmdname) first argument ("/x myvar" for example, to print myvar in hex). */ static void -print_command_1 (char *exp, int inspect, int voidprint) +print_command_1 (char *exp, int voidprint) { struct expression *expr; struct cleanup *old_chain = 0; @@ -982,17 +978,13 @@ print_command_1 (char *exp, int inspect, int voidprint) else annotate_value_begin (value_type (val)); - if (inspect) - printf_unfiltered ("\031(gdb-makebuffer \"%s\" %d '(\"", - exp, histindex); - else if (histindex >= 0) + if (histindex >= 0) printf_filtered ("$%d = ", histindex); if (histindex >= 0) annotate_value_history_value (); get_formatted_print_options (&opts, format); - opts.inspect_it = inspect; opts.raw = fmt.raw; print_formatted (val, fmt.size, &opts, gdb_stdout); @@ -1002,9 +994,6 @@ print_command_1 (char *exp, int inspect, int voidprint) annotate_value_history_end (); else annotate_value_end (); - - if (inspect) - printf_unfiltered ("\") )\030"); } if (cleanup) @@ -1014,23 +1003,14 @@ print_command_1 (char *exp, int inspect, int voidprint) static void print_command (char *exp, int from_tty) { - print_command_1 (exp, 0, 1); -} - -/* Same as print, except in epoch, it gets its own window. */ -static void -inspect_command (char *exp, int from_tty) -{ - extern int epoch_interface; - - print_command_1 (exp, epoch_interface, 1); + print_command_1 (exp, 1); } /* Same as print, except it doesn't print void results. */ static void call_command (char *exp, int from_tty) { - print_command_1 (exp, 0, 0); + print_command_1 (exp, 0); } void @@ -1080,6 +1060,22 @@ set_command (char *exp, int from_tty) struct cleanup *old_chain = make_cleanup (free_current_contents, &expr); + if (expr->nelts >= 1) + switch (expr->elts[0].opcode) + { + case UNOP_PREINCREMENT: + case UNOP_POSTINCREMENT: + case UNOP_PREDECREMENT: + case UNOP_POSTDECREMENT: + case BINOP_ASSIGN: + case BINOP_ASSIGN_MODIFY: + case BINOP_COMMA: + break; + default: + warning + (_("Expression is not an assignment (and might have no effect)")); + } + evaluate_expression (expr); do_cleanups (old_chain); } @@ -1186,8 +1182,7 @@ address_info (char *exp, int from_tty) long val; struct obj_section *section; CORE_ADDR load_addr, context_pc = 0; - int is_a_field_of_this; /* C++: lookup_symbol sets this to nonzero - if exp is a field of `this'. */ + struct field_of_this_result is_a_field_of_this; if (exp == 0) error (_("Argument required.")); @@ -1196,7 +1191,7 @@ address_info (char *exp, int from_tty) &is_a_field_of_this); if (sym == NULL) { - if (is_a_field_of_this) + if (is_a_field_of_this.type != NULL) { printf_filtered ("Symbol \""); fprintf_symbol_filtered (gdb_stdout, exp, @@ -1594,7 +1589,6 @@ map_display_numbers (char *args, void *data) { struct get_number_or_range_state state; - struct display *b, *tmp; int num; if (args == NULL) @@ -1637,9 +1631,6 @@ do_delete_display (struct display *d, void *data) static void undisplay_command (char *args, int from_tty) { - int num; - struct get_number_or_range_state state; - if (args == NULL) { if (query (_("Delete all auto-display expressions? "))) @@ -1952,7 +1943,9 @@ clear_dangling_display_expressions (struct so_list *solib) struct symbol. NAME is the name to print; if NULL then VAR's print name will be used. STREAM is the ui_file on which to print the value. INDENT specifies the number of indent levels to print - before printing the variable name. */ + before printing the variable name. + + This function invalidates FRAME. */ void print_variable_and_value (const char *name, struct symbol *var, @@ -1974,6 +1967,10 @@ print_variable_and_value (const char *name, struct symbol *var, get_user_print_options (&opts); opts.deref_ref = 1; common_val_print (val, stream, indent, &opts, current_language); + + /* common_val_print invalidates FRAME when a pretty printer calls inferior + function. */ + frame = NULL; } if (except.reason < 0) fprintf_filtered(stream, "", name, @@ -1981,341 +1978,296 @@ print_variable_and_value (const char *name, struct symbol *var, fprintf_filtered (stream, "\n"); } -/* printf "printf format string" ARG to STREAM. */ +/* Subroutine of ui_printf to simplify it. + Print VALUE to STREAM using FORMAT. + VALUE is a C-style string on the target. */ static void -ui_printf (char *arg, struct ui_file *stream) +printf_c_string (struct ui_file *stream, const char *format, + struct value *value) { - char *f = NULL; - char *s = arg; - char *string = NULL; - struct value **val_args; - char *substrings; - char *current_substring; - int nargs = 0; - int allocated_args = 20; - struct cleanup *old_cleanups; + gdb_byte *str; + CORE_ADDR tem; + int j; - val_args = xmalloc (allocated_args * sizeof (struct value *)); - old_cleanups = make_cleanup (free_current_contents, &val_args); + tem = value_as_address (value); - if (s == 0) - error_no_arg (_("format-control string and values to print")); + /* This is a %s argument. Find the length of the string. */ + for (j = 0;; j++) + { + gdb_byte c; - s = skip_spaces (s); + QUIT; + read_memory (tem + j, &c, 1); + if (c == 0) + break; + } - /* A format string should follow, enveloped in double quotes. */ - if (*s++ != '"') - error (_("Bad format string, missing '\"'.")); + /* Copy the string contents into a string inside GDB. */ + str = (gdb_byte *) alloca (j + 1); + if (j != 0) + read_memory (tem, str, j); + str[j] = 0; - /* Parse the format-control string and copy it into the string STRING, - processing some kinds of escape sequence. */ + fprintf_filtered (stream, format, (char *) str); +} + +/* Subroutine of ui_printf to simplify it. + Print VALUE to STREAM using FORMAT. + VALUE is a wide C-style string on the target. */ + +static void +printf_wide_c_string (struct ui_file *stream, const char *format, + struct value *value) +{ + gdb_byte *str; + CORE_ADDR tem; + int j; + struct gdbarch *gdbarch = get_type_arch (value_type (value)); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct type *wctype = lookup_typename (current_language, gdbarch, + "wchar_t", NULL, 0); + int wcwidth = TYPE_LENGTH (wctype); + gdb_byte *buf = alloca (wcwidth); + struct obstack output; + struct cleanup *inner_cleanup; - f = string = (char *) alloca (strlen (s) + 1); + tem = value_as_address (value); - while (*s != '"') + /* This is a %s argument. Find the length of the string. */ + for (j = 0;; j += wcwidth) { - int c = *s++; - switch (c) - { - case '\0': - error (_("Bad format string, non-terminated '\"'.")); + QUIT; + read_memory (tem + j, buf, wcwidth); + if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0) + break; + } - case '\\': - switch (c = *s++) - { - case '\\': - *f++ = '\\'; - break; - case 'a': - *f++ = '\a'; - break; - case 'b': - *f++ = '\b'; - break; - case 'f': - *f++ = '\f'; - break; - case 'n': - *f++ = '\n'; - break; - case 'r': - *f++ = '\r'; - break; - case 't': - *f++ = '\t'; - break; - case 'v': - *f++ = '\v'; - break; - case '"': - *f++ = '"'; - break; - default: - /* ??? TODO: handle other escape sequences. */ - error (_("Unrecognized escape character \\%c in format string."), - c); - } - 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); - default: - *f++ = c; + obstack_init (&output); + inner_cleanup = make_cleanup_obstack_free (&output); + + convert_between_encodings (target_wide_charset (gdbarch), + host_charset (), + str, j, wcwidth, + &output, translit_char); + obstack_grow_str0 (&output, ""); + + fprintf_filtered (stream, format, obstack_base (&output)); + do_cleanups (inner_cleanup); +} + +/* Subroutine of ui_printf to simplify it. + Print VALUE, a decimal floating point value, to STREAM using FORMAT. */ + +static void +printf_decfloat (struct ui_file *stream, const char *format, + struct value *value) +{ + const gdb_byte *param_ptr = value_contents (value); + +#if defined (PRINTF_HAS_DECFLOAT) + /* If we have native support for Decimal floating + printing, handle it here. */ + fprintf_filtered (stream, format, param_ptr); +#else + /* As a workaround until vasprintf has native support for DFP + we convert the DFP values to string and print them using + the %s format specifier. */ + const char *p; + + /* Parameter data. */ + struct type *param_type = value_type (value); + struct gdbarch *gdbarch = get_type_arch (param_type); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + + /* DFP output data. */ + struct value *dfp_value = NULL; + gdb_byte *dfp_ptr; + int dfp_len = 16; + gdb_byte dec[16]; + struct type *dfp_type = NULL; + char decstr[MAX_DECIMAL_STRING]; + + /* Points to the end of the string so that we can go back + and check for DFP length modifiers. */ + p = format + strlen (format); + + /* Look for the float/double format specifier. */ + while (*p != 'f' && *p != 'e' && *p != 'E' + && *p != 'g' && *p != 'G') + p--; + + /* Search for the '%' char and extract the size and type of + the output decimal value based on its modifiers + (%Hf, %Df, %DDf). */ + while (*--p != '%') + { + if (*p == 'H') + { + dfp_len = 4; + dfp_type = builtin_type (gdbarch)->builtin_decfloat; + } + else if (*p == 'D' && *(p - 1) == 'D') + { + dfp_len = 16; + dfp_type = builtin_type (gdbarch)->builtin_declong; + p--; + } + else + { + dfp_len = 8; + dfp_type = builtin_type (gdbarch)->builtin_decdouble; } } - /* Skip over " and following space and comma. */ - s++; - *f++ = '\0'; - s = skip_spaces (s); + /* Conversion between different DFP types. */ + if (TYPE_CODE (param_type) == TYPE_CODE_DECFLOAT) + decimal_convert (param_ptr, TYPE_LENGTH (param_type), + byte_order, dec, dfp_len, byte_order); + else + /* If this is a non-trivial conversion, just output 0. + A correct converted value can be displayed by explicitly + casting to a DFP type. */ + decimal_from_string (dec, dfp_len, byte_order, "0"); - if (*s != ',' && *s != 0) - error (_("Invalid argument syntax")); + dfp_value = value_from_decfloat (dfp_type, dec); - if (*s == ',') - s++; - s = skip_spaces (s); + dfp_ptr = (gdb_byte *) value_contents (dfp_value); - /* Need extra space for the '\0's. Doubling the size is sufficient. */ - substrings = alloca (strlen (string) * 2); - current_substring = substrings; + decimal_to_string (dfp_ptr, dfp_len, byte_order, decstr); - { - /* Now scan the string for %-specs and see what kinds of args they want. - argclass[I] classifies the %-specs so we can give printf_filtered - something of the right size. */ + /* Print the DFP value. */ + fprintf_filtered (stream, "%s", decstr); +#endif +} - enum argclass - { - 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; - enum argclass this_argclass; - char *last_arg; - int nargs_wanted; - int i; +/* Subroutine of ui_printf to simplify it. + Print VALUE, a target pointer, to STREAM using FORMAT. */ - argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass); - nargs_wanted = 0; - f = string; - last_arg = string; - while (*f) - if (*f++ == '%') - { - int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0; - int seen_space = 0, seen_plus = 0; - int seen_big_l = 0, seen_h = 0, seen_big_h = 0; - int seen_big_d = 0, seen_double_big_d = 0; - int bad = 0; - - /* Check the validity of the format specifier, and work - out what argument it expects. We only accept C89 - format strings, with the exception of long long (which - we autoconf for). */ - - /* Skip over "%%". */ - if (*f == '%') - { - f++; - continue; - } +static void +printf_pointer (struct ui_file *stream, const char *format, + struct value *value) +{ + /* We avoid the host's %p because pointers are too + likely to be the wrong size. The only interesting + modifier for %p is a width; extract that, and then + handle %p as glibc would: %#x or a literal "(nil)". */ + + const char *p; + char *fmt, *fmt_p; +#ifdef PRINTF_HAS_LONG_LONG + long long val = value_as_long (value); +#else + long val = value_as_long (value); +#endif - /* The first part of a format specifier is a set of flag - characters. */ - while (strchr ("0-+ #", *f)) - { - if (*f == '#') - seen_hash = 1; - else if (*f == '0') - seen_zero = 1; - else if (*f == ' ') - seen_space = 1; - else if (*f == '+') - seen_plus = 1; - f++; - } + fmt = alloca (strlen (format) + 5); - /* The next part of a format specifier is a width. */ - while (strchr ("0123456789", *f)) - f++; + /* Copy up to the leading %. */ + p = format; + fmt_p = fmt; + while (*p) + { + int is_percent = (*p == '%'); - /* The next part of a format specifier is a precision. */ - if (*f == '.') - { - seen_prec = 1; - f++; - while (strchr ("0123456789", *f)) - f++; - } + *fmt_p++ = *p++; + if (is_percent) + { + if (*p == '%') + *fmt_p++ = *p++; + else + break; + } + } - /* The next part of a format specifier is a length modifier. */ - if (*f == 'h') - { - seen_h = 1; - f++; - } - else if (*f == 'l') - { - f++; - lcount++; - if (*f == 'l') - { - f++; - lcount++; - } - } - else if (*f == 'L') - { - seen_big_l = 1; - f++; - } - /* Decimal32 modifier. */ - else if (*f == 'H') - { - seen_big_h = 1; - f++; - } - /* Decimal64 and Decimal128 modifiers. */ - else if (*f == 'D') - { - f++; - - /* Check for a Decimal128. */ - if (*f == 'D') - { - f++; - seen_double_big_d = 1; - } - else - seen_big_d = 1; - } + if (val != 0) + *fmt_p++ = '#'; - switch (*f) - { - case 'u': - if (seen_hash) - bad = 1; - /* FALLTHROUGH */ - - case 'o': - case 'x': - case 'X': - if (seen_space || seen_plus) - bad = 1; - /* FALLTHROUGH */ - - case 'd': - case 'i': - if (lcount == 0) - this_argclass = int_arg; - else if (lcount == 1) - this_argclass = long_arg; - else - this_argclass = long_long_arg; - - if (seen_big_l) - bad = 1; - break; + /* Copy any width. */ + while (*p >= '0' && *p < '9') + *fmt_p++ = *p++; - case 'c': - 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; - break; + gdb_assert (*p == 'p' && *(p + 1) == '\0'); + if (val != 0) + { +#ifdef PRINTF_HAS_LONG_LONG + *fmt_p++ = 'l'; +#endif + *fmt_p++ = 'l'; + *fmt_p++ = 'x'; + *fmt_p++ = '\0'; + fprintf_filtered (stream, fmt, val); + } + else + { + *fmt_p++ = 's'; + *fmt_p++ = '\0'; + fprintf_filtered (stream, fmt, "(nil)"); + } +} - case 'p': - this_argclass = ptr_arg; - if (lcount || seen_h || seen_big_l) - bad = 1; - if (seen_prec || seen_zero || seen_space || seen_plus) - bad = 1; - break; +/* printf "printf format string" ARG to STREAM. */ - case 's': - 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; - break; +static void +ui_printf (const char *arg, struct ui_file *stream) +{ + struct format_piece *fpieces; + const char *s = arg; + struct value **val_args; + int allocated_args = 20; + struct cleanup *old_cleanups; - case 'e': - case 'f': - case 'g': - case 'E': - case 'G': - if (seen_big_h || seen_big_d || seen_double_big_d) - this_argclass = decfloat_arg; - else if (seen_big_l) - this_argclass = long_double_arg; - else - this_argclass = double_arg; - - if (lcount || seen_h) - bad = 1; - break; + val_args = xmalloc (allocated_args * sizeof (struct value *)); + old_cleanups = make_cleanup (free_current_contents, &val_args); - case '*': - error (_("`*' not supported for precision or width in printf")); + if (s == 0) + error_no_arg (_("format-control string and values to print")); - case 'n': - error (_("Format specifier `n' not supported in printf")); + s = skip_spaces_const (s); - case '\0': - error (_("Incomplete format specifier at end of format string")); + /* A format string should follow, enveloped in double quotes. */ + if (*s++ != '"') + error (_("Bad format string, missing '\"'.")); - default: - error (_("Unrecognized format specifier '%c' in printf"), *f); - } + fpieces = parse_format_string (&s); - if (bad) - error (_("Inappropriate modifiers to " - "format specifier '%c' in printf"), - *f); + make_cleanup (free_format_pieces_cleanup, &fpieces); - f++; + if (*s++ != '"') + error (_("Bad format string, non-terminated '\"'.")); + + s = skip_spaces_const (s); - if (lcount > 1 && USE_PRINTF_I64) - { - /* Windows' printf does support long long, but not the usual way. - Convert %lld to %I64d. */ - int length_before_ll = f - last_arg - 1 - lcount; - - strncpy (current_substring, last_arg, length_before_ll); - strcpy (current_substring + length_before_ll, "I64"); - current_substring[length_before_ll + 3] = - 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; + if (*s != ',' && *s != 0) + error (_("Invalid argument syntax")); - 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); - current_substring += f - last_arg; - } - *current_substring++ = '\0'; - last_arg = f; - argclass[nargs_wanted++] = this_argclass; - } + if (*s == ',') + s++; + s = skip_spaces_const (s); + + { + int nargs = 0; + int nargs_wanted; + int i, fr; + char *current_substring; + + nargs_wanted = 0; + for (fr = 0; fpieces[fr].string != NULL; fr++) + if (fpieces[fr].argclass != literal_piece) + ++nargs_wanted; /* Now, parse all arguments and evaluate them. Store the VALUEs in VAL_ARGS. */ while (*s != '\0') { - char *s1; + const char *s1; if (nargs == allocated_args) val_args = (struct value **) xrealloc ((char *) val_args, @@ -2334,84 +2286,17 @@ ui_printf (char *arg, struct ui_file *stream) error (_("Wrong number of arguments for specified format-string")); /* Now actually print them. */ - current_substring = substrings; - for (i = 0; i < nargs; i++) + i = 0; + for (fr = 0; fpieces[fr].string != NULL; fr++) { - switch (argclass[i]) + current_substring = fpieces[fr].string; + switch (fpieces[fr].argclass) { case string_arg: - { - gdb_byte *str; - CORE_ADDR tem; - int j; - - tem = value_as_address (val_args[i]); - - /* This is a %s argument. Find the length of the string. */ - for (j = 0;; j++) - { - gdb_byte c; - - QUIT; - read_memory (tem + j, &c, 1); - if (c == 0) - break; - } - - /* Copy the string contents into a string inside GDB. */ - str = (gdb_byte *) alloca (j + 1); - if (j != 0) - read_memory (tem, str, j); - str[j] = 0; - - fprintf_filtered (stream, current_substring, (char *) str); - } + printf_c_string (stream, current_substring, val_args[i]); break; case wide_string_arg: - { - gdb_byte *str; - CORE_ADDR tem; - int j; - struct gdbarch *gdbarch - = get_type_arch (value_type (val_args[i])); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct type *wctype = lookup_typename (current_language, gdbarch, - "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, byte_order) == 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 (gdbarch), - host_charset (), - str, j, wcwidth, - &output, translit_char); - obstack_grow_str0 (&output, ""); - - fprintf_filtered (stream, current_substring, - obstack_base (&output)); - do_cleanups (inner_cleanup); - } + printf_wide_c_string (stream, current_substring, val_args[i]); break; case wide_char_arg: { @@ -2484,7 +2369,7 @@ ui_printf (char *arg, struct ui_file *stream) error (_("long double not supported in printf")); #endif case long_long_arg: -#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG) +#ifdef PRINTF_HAS_LONG_LONG { long long val = value_as_long (val_args[i]); @@ -2508,184 +2393,32 @@ ui_printf (char *arg, struct ui_file *stream) fprintf_filtered (stream, current_substring, val); break; } - /* Handles decimal floating values. */ - case decfloat_arg: - { - const gdb_byte *param_ptr = value_contents (val_args[i]); - -#if defined (PRINTF_HAS_DECFLOAT) - /* If we have native support for Decimal floating - printing, handle it here. */ - fprintf_filtered (stream, current_substring, param_ptr); -#else - - /* As a workaround until vasprintf has native support for DFP - we convert the DFP values to string and print them using - the %s format specifier. */ - - char *eos, *sos; - int nnull_chars = 0; - - /* Parameter data. */ - struct type *param_type = value_type (val_args[i]); - unsigned int param_len = TYPE_LENGTH (param_type); - struct gdbarch *gdbarch = get_type_arch (param_type); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - - /* DFP output data. */ - struct value *dfp_value = NULL; - gdb_byte *dfp_ptr; - int dfp_len = 16; - gdb_byte dec[16]; - struct type *dfp_type = NULL; - char decstr[MAX_DECIMAL_STRING]; - - /* Points to the end of the string so that we can go back - and check for DFP length modifiers. */ - eos = current_substring + strlen (current_substring); - - /* Look for the float/double format specifier. */ - while (*eos != 'f' && *eos != 'e' && *eos != 'E' - && *eos != 'g' && *eos != 'G') - eos--; - - sos = eos; - - /* Search for the '%' char and extract the size and type of - the output decimal value based on its modifiers - (%Hf, %Df, %DDf). */ - while (*--sos != '%') - { - if (*sos == 'H') - { - dfp_len = 4; - dfp_type = builtin_type (gdbarch)->builtin_decfloat; - } - else if (*sos == 'D' && *(sos - 1) == 'D') - { - dfp_len = 16; - dfp_type = builtin_type (gdbarch)->builtin_declong; - sos--; - } - else - { - dfp_len = 8; - dfp_type = builtin_type (gdbarch)->builtin_decdouble; - } - } - - /* Replace %Hf, %Df and %DDf with %s's. */ - *++sos = 's'; - - /* Go through the whole format string and pull the correct - number of chars back to compensate for the change in the - format specifier. */ - while (nnull_chars < nargs - i) - { - if (*eos == '\0') - nnull_chars++; - - *++sos = *++eos; - } - - /* Conversion between different DFP types. */ - if (TYPE_CODE (param_type) == TYPE_CODE_DECFLOAT) - decimal_convert (param_ptr, param_len, byte_order, - dec, dfp_len, byte_order); - else - /* If this is a non-trivial conversion, just output 0. - A correct converted value can be displayed by explicitly - casting to a DFP type. */ - decimal_from_string (dec, dfp_len, byte_order, "0"); - - dfp_value = value_from_decfloat (dfp_type, dec); - - dfp_ptr = (gdb_byte *) value_contents (dfp_value); - - decimal_to_string (dfp_ptr, dfp_len, byte_order, decstr); - - /* Print the DFP value. */ - fprintf_filtered (stream, current_substring, decstr); - - break; -#endif - } - + case decfloat_arg: + printf_decfloat (stream, current_substring, val_args[i]); + break; case ptr_arg: - { - /* We avoid the host's %p because pointers are too - likely to be the wrong size. The only interesting - modifier for %p is a width; extract that, and then - handle %p as glibc would: %#x or a literal "(nil)". */ - - char *p, *fmt, *fmt_p; -#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG) - long long val = value_as_long (val_args[i]); -#else - long val = value_as_long (val_args[i]); -#endif - - fmt = alloca (strlen (current_substring) + 5); - - /* Copy up to the leading %. */ - p = current_substring; - fmt_p = fmt; - while (*p) - { - int is_percent = (*p == '%'); - - *fmt_p++ = *p++; - if (is_percent) - { - if (*p == '%') - *fmt_p++ = *p++; - else - break; - } - } - - if (val != 0) - *fmt_p++ = '#'; - - /* Copy any width. */ - while (*p >= '0' && *p < '9') - *fmt_p++ = *p++; - - gdb_assert (*p == 'p' && *(p + 1) == '\0'); - if (val != 0) - { -#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG) - *fmt_p++ = 'l'; -#endif - *fmt_p++ = 'l'; - *fmt_p++ = 'x'; - *fmt_p++ = '\0'; - fprintf_filtered (stream, fmt, val); - } - else - { - *fmt_p++ = 's'; - *fmt_p++ = '\0'; - fprintf_filtered (stream, fmt, "(nil)"); - } - - break; - } + printf_pointer (stream, current_substring, val_args[i]); + break; + case literal_piece: + /* Print a portion of the format string that has no + directives. Note that this will not include any + ordinary %-specs, but it might include "%%". That is + why we use printf_filtered and not puts_filtered here. + Also, we pass a dummy argument because some platforms + have modified GCC to include -Wformat-security by + default, which will warn here if there is no + argument. */ + fprintf_filtered (stream, current_substring, 0); + break; default: internal_error (__FILE__, __LINE__, _("failed internal consistency check")); } - /* Skip to the next substring. */ - current_substring += strlen (current_substring) + 1; + /* Maybe advance to the next argument. */ + if (fpieces[fr].argclass != literal_piece) + ++i; } - /* Print the portion of the format string after the last argument. - Note that this will not include any ordinary %-specs, but it - might include "%%". That is why we use printf_filtered and not - puts_filtered here. Also, we pass a dummy argument because - some platforms have modified GCC to include -Wformat-security - by default, which will warn here if there is no argument. */ - fprintf_filtered (stream, last_arg, 0); } do_cleanups (old_cleanups); } @@ -2860,11 +2593,7 @@ EXP may be preceded with /FMT, where FMT is a format letter\n\ but no count or size letter (see \"x\" command).")); set_cmd_completer (c, expression_completer); add_com_alias ("p", "print", class_vars, 1); - - c = add_com ("inspect", class_vars, inspect_command, _("\ -Same as \"print\" command, except that if you are running in the epoch\n\ -environment, the value is printed in its own window.")); - set_cmd_completer (c, expression_completer); + add_com_alias ("inspect", "print", class_vars, 1); add_setshow_uinteger_cmd ("max-symbolic-offset", no_class, &max_symbolic_offset, _("\ diff --git a/contrib/gdb-7/gdb/probe.c b/contrib/gdb-7/gdb/probe.c new file mode 100644 index 0000000000..dfb6e7eec1 --- /dev/null +++ b/contrib/gdb-7/gdb/probe.c @@ -0,0 +1,760 @@ +/* Generic static probe support for GDB. + + Copyright (C) 2012-2013 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 "probe.h" +#include "command.h" +#include "cli/cli-cmds.h" +#include "cli/cli-utils.h" +#include "objfiles.h" +#include "symtab.h" +#include "progspace.h" +#include "filenames.h" +#include "exceptions.h" +#include "linespec.h" +#include "gdb_regex.h" +#include "frame.h" +#include "arch-utils.h" +#include + + + +/* See definition in probe.h. */ + +struct symtabs_and_lines +parse_probes (char **argptr, struct linespec_result *canonical) +{ + char *arg_start, *arg_end, *arg; + char *objfile_name = NULL, *provider = NULL, *name, *p; + struct cleanup *cleanup; + struct symtabs_and_lines result; + struct objfile *objfile; + struct program_space *pspace; + const struct probe_ops *probe_ops; + const char *cs; + + result.sals = NULL; + result.nelts = 0; + + arg_start = *argptr; + + cs = *argptr; + probe_ops = probe_linespec_to_ops (&cs); + gdb_assert (probe_ops != NULL); + + arg = (char *) cs; + arg = skip_spaces (arg); + if (!*arg) + error (_("argument to `%s' missing"), arg_start); + + arg_end = skip_to_space (arg); + + /* We make a copy here so we can write over parts with impunity. */ + arg = savestring (arg, arg_end - arg); + cleanup = make_cleanup (xfree, arg); + + /* Extract each word from the argument, separated by ":"s. */ + p = strchr (arg, ':'); + if (p == NULL) + { + /* This is `-p name'. */ + name = arg; + } + else + { + char *hold = p + 1; + + *p = '\0'; + p = strchr (hold, ':'); + if (p == NULL) + { + /* This is `-p provider:name'. */ + provider = arg; + name = hold; + } + else + { + /* This is `-p objfile:provider:name'. */ + *p = '\0'; + objfile_name = arg; + provider = hold; + name = p + 1; + } + } + + if (*name == '\0') + error (_("no probe name specified")); + if (provider && *provider == '\0') + error (_("invalid provider name")); + if (objfile_name && *objfile_name == '\0') + error (_("invalid objfile name")); + + ALL_PSPACES (pspace) + ALL_PSPACE_OBJFILES (pspace, objfile) + { + VEC (probe_p) *probes; + struct probe *probe; + int ix; + + if (!objfile->sf || !objfile->sf->sym_probe_fns) + continue; + + if (objfile_name + && FILENAME_CMP (objfile->name, objfile_name) != 0 + && FILENAME_CMP (lbasename (objfile->name), objfile_name) != 0) + continue; + + probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile); + + for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++) + { + struct symtab_and_line *sal; + + if (probe_ops != &probe_ops_any && probe->pops != probe_ops) + continue; + + if (provider && strcmp (probe->provider, provider) != 0) + continue; + + if (strcmp (probe->name, name) != 0) + continue; + + ++result.nelts; + result.sals = xrealloc (result.sals, + result.nelts + * sizeof (struct symtab_and_line)); + sal = &result.sals[result.nelts - 1]; + + init_sal (sal); + + sal->pc = probe->address; + sal->explicit_pc = 1; + sal->section = find_pc_overlay (sal->pc); + sal->pspace = pspace; + sal->probe = probe; + } + } + + if (result.nelts == 0) + { + throw_error (NOT_FOUND_ERROR, + _("No probe matching objfile=`%s', provider=`%s', name=`%s'"), + objfile_name ? objfile_name : _(""), + provider ? provider : _(""), + name); + } + + if (canonical) + { + canonical->special_display = 1; + canonical->pre_expanded = 1; + canonical->addr_string = savestring (*argptr, arg_end - *argptr); + } + + *argptr = arg_end; + do_cleanups (cleanup); + + return result; +} + +/* See definition in probe.h. */ + +VEC (probe_p) * +find_probes_in_objfile (struct objfile *objfile, const char *provider, + const char *name) +{ + VEC (probe_p) *probes, *result = NULL; + int ix; + struct probe *probe; + + if (!objfile->sf || !objfile->sf->sym_probe_fns) + return NULL; + + probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile); + for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++) + { + if (strcmp (probe->provider, provider) != 0) + continue; + + if (strcmp (probe->name, name) != 0) + continue; + + VEC_safe_push (probe_p, result, probe); + } + + return result; +} + +/* See definition in probe.h. */ + +struct probe * +find_probe_by_pc (CORE_ADDR pc) +{ + struct objfile *objfile; + + ALL_OBJFILES (objfile) + { + VEC (probe_p) *probes; + int ix; + struct probe *probe; + + if (!objfile->sf || !objfile->sf->sym_probe_fns) + continue; + + /* If this proves too inefficient, we can replace with a hash. */ + probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile); + for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++) + if (probe->address == pc) + return probe; + } + + return NULL; +} + + + +/* A helper function for collect_probes that compiles a regexp and + throws an exception on error. This installs a cleanup to free the + resulting pattern on success. If RX is NULL, this does nothing. */ + +static void +compile_rx_or_error (regex_t *pattern, const char *rx, const char *message) +{ + int code; + + if (!rx) + return; + + code = regcomp (pattern, rx, REG_NOSUB); + if (code == 0) + make_regfree_cleanup (pattern); + else + { + char *err = get_regcomp_error (code, pattern); + + make_cleanup (xfree, err); + error (("%s: %s"), message, err); + } +} + +/* Make a vector of probes matching OBJNAME, PROVIDER, and PROBE_NAME. + If POPS is not NULL, only probes of this certain probe_ops will match. + Each argument is a regexp, or NULL, which matches anything. */ + +static VEC (probe_p) * +collect_probes (char *objname, char *provider, char *probe_name, + const struct probe_ops *pops) +{ + struct objfile *objfile; + VEC (probe_p) *result = NULL; + struct cleanup *cleanup, *cleanup_temps; + regex_t obj_pat, prov_pat, probe_pat; + + cleanup = make_cleanup (VEC_cleanup (probe_p), &result); + + cleanup_temps = make_cleanup (null_cleanup, NULL); + compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp")); + compile_rx_or_error (&probe_pat, probe_name, _("Invalid probe regexp")); + compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp")); + + ALL_OBJFILES (objfile) + { + VEC (probe_p) *probes; + struct probe *probe; + int ix; + + if (! objfile->sf || ! objfile->sf->sym_probe_fns) + continue; + + if (objname) + { + if (regexec (&obj_pat, objfile->name, 0, NULL, 0) != 0) + continue; + } + + probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile); + + for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++) + { + if (pops != NULL && probe->pops != pops) + continue; + + if (provider + && regexec (&prov_pat, probe->provider, 0, NULL, 0) != 0) + continue; + + if (probe_name + && regexec (&probe_pat, probe->name, 0, NULL, 0) != 0) + continue; + + VEC_safe_push (probe_p, result, probe); + } + } + + do_cleanups (cleanup_temps); + discard_cleanups (cleanup); + return result; +} + +/* A qsort comparison function for probe_p objects. */ + +static int +compare_probes (const void *a, const void *b) +{ + const struct probe *pa = *((const struct probe **) a); + const struct probe *pb = *((const struct probe **) b); + int v; + + v = strcmp (pa->provider, pb->provider); + if (v) + return v; + + v = strcmp (pa->name, pb->name); + if (v) + return v; + + if (pa->address < pb->address) + return -1; + if (pa->address > pb->address) + return 1; + + return strcmp (pa->objfile->name, pb->objfile->name); +} + +/* Helper function that generate entries in the ui_out table being + crafted by `info_probes_for_ops'. */ + +static void +gen_ui_out_table_header_info (VEC (probe_p) *probes, + const struct probe_ops *p) +{ + /* `headings' refers to the names of the columns when printing `info + probes'. */ + VEC (info_probe_column_s) *headings = NULL; + struct cleanup *c; + info_probe_column_s *column; + size_t headings_size; + int ix; + + gdb_assert (p != NULL); + + if (p->gen_info_probes_table_header == NULL + && p->gen_info_probes_table_values == NULL) + return; + + gdb_assert (p->gen_info_probes_table_header != NULL + && p->gen_info_probes_table_values != NULL); + + c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings); + p->gen_info_probes_table_header (&headings); + + headings_size = VEC_length (info_probe_column_s, headings); + + for (ix = 0; + VEC_iterate (info_probe_column_s, headings, ix, column); + ++ix) + { + struct probe *probe; + int jx; + size_t size_max = strlen (column->print_name); + + for (jx = 0; VEC_iterate (probe_p, probes, jx, probe); ++jx) + { + /* `probe_fields' refers to the values of each new field that this + probe will display. */ + VEC (const_char_ptr) *probe_fields = NULL; + struct cleanup *c2; + const char *val; + int kx; + + if (probe->pops != p) + continue; + + c2 = make_cleanup (VEC_cleanup (const_char_ptr), &probe_fields); + p->gen_info_probes_table_values (probe, &probe_fields); + + gdb_assert (VEC_length (const_char_ptr, probe_fields) + == headings_size); + + for (kx = 0; VEC_iterate (const_char_ptr, probe_fields, kx, val); + ++kx) + { + /* It is valid to have a NULL value here, which means that the + backend does not have something to write and this particular + field should be skipped. */ + if (val == NULL) + continue; + + size_max = max (strlen (val), size_max); + } + do_cleanups (c2); + } + + ui_out_table_header (current_uiout, size_max, ui_left, + column->field_name, column->print_name); + } + + do_cleanups (c); +} + +/* Helper function to print extra information about a probe and an objfile + represented by PROBE. */ + +static void +print_ui_out_info (struct probe *probe) +{ + int ix; + int j = 0; + /* `values' refers to the actual values of each new field in the output + of `info probe'. `headings' refers to the names of each new field. */ + VEC (const_char_ptr) *values = NULL; + VEC (info_probe_column_s) *headings = NULL; + info_probe_column_s *column; + struct cleanup *c; + + gdb_assert (probe != NULL); + gdb_assert (probe->pops != NULL); + + if (probe->pops->gen_info_probes_table_header == NULL + && probe->pops->gen_info_probes_table_values == NULL) + return; + + gdb_assert (probe->pops->gen_info_probes_table_header != NULL + && probe->pops->gen_info_probes_table_values != NULL); + + c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings); + make_cleanup (VEC_cleanup (const_char_ptr), &values); + + probe->pops->gen_info_probes_table_header (&headings); + probe->pops->gen_info_probes_table_values (probe, &values); + + gdb_assert (VEC_length (info_probe_column_s, headings) + == VEC_length (const_char_ptr, values)); + + for (ix = 0; + VEC_iterate (info_probe_column_s, headings, ix, column); + ++ix) + { + const char *val = VEC_index (const_char_ptr, values, j++); + + if (val == NULL) + ui_out_field_skip (current_uiout, column->field_name); + else + ui_out_field_string (current_uiout, column->field_name, val); + } + + do_cleanups (c); +} + +/* Helper function that returns the number of extra fields which POPS will + need. */ + +static int +get_number_extra_fields (const struct probe_ops *pops) +{ + VEC (info_probe_column_s) *headings = NULL; + struct cleanup *c; + int n; + + if (pops->gen_info_probes_table_header == NULL) + return 0; + + c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings); + pops->gen_info_probes_table_header (&headings); + + n = VEC_length (info_probe_column_s, headings); + + do_cleanups (c); + + return n; +} + +/* See comment in probe.h. */ + +void +info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops) +{ + char *provider, *probe_name = NULL, *objname = NULL; + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); + VEC (probe_p) *probes; + int i, any_found; + int ui_out_extra_fields = 0; + size_t size_addr; + size_t size_name = strlen ("Name"); + size_t size_objname = strlen ("Object"); + size_t size_provider = strlen ("Provider"); + struct probe *probe; + struct gdbarch *gdbarch = get_current_arch (); + + /* Do we have a `provider:probe:objfile' style of linespec? */ + provider = extract_arg (&arg); + if (provider) + { + make_cleanup (xfree, provider); + + probe_name = extract_arg (&arg); + if (probe_name) + { + make_cleanup (xfree, probe_name); + + objname = extract_arg (&arg); + if (objname) + make_cleanup (xfree, objname); + } + } + + if (pops == NULL) + { + const struct probe_ops *po; + int ix; + + /* If the probe_ops is NULL, it means the user has requested a "simple" + `info probes', i.e., she wants to print all information about all + probes. For that, we have to identify how many extra fields we will + need to add in the ui_out table. + + To do that, we iterate over all probe_ops, querying each one about + its extra fields, and incrementing `ui_out_extra_fields' to reflect + that number. */ + + for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix) + ui_out_extra_fields += get_number_extra_fields (po); + } + else + ui_out_extra_fields = get_number_extra_fields (pops); + + probes = collect_probes (objname, provider, probe_name, pops); + make_cleanup (VEC_cleanup (probe_p), &probes); + make_cleanup_ui_out_table_begin_end (current_uiout, + 4 + ui_out_extra_fields, + VEC_length (probe_p, probes), + "StaticProbes"); + + if (!VEC_empty (probe_p, probes)) + qsort (VEC_address (probe_p, probes), VEC_length (probe_p, probes), + sizeof (probe_p), compare_probes); + + /* What's the size of an address in our architecture? */ + size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10; + + /* Determining the maximum size of each field (`provider', `name' and + `objname'). */ + for (i = 0; VEC_iterate (probe_p, probes, i, probe); ++i) + { + size_name = max (strlen (probe->name), size_name); + size_provider = max (strlen (probe->provider), size_provider); + size_objname = max (strlen (probe->objfile->name), size_objname); + } + + ui_out_table_header (current_uiout, size_provider, ui_left, "provider", + _("Provider")); + ui_out_table_header (current_uiout, size_name, ui_left, "name", _("Name")); + ui_out_table_header (current_uiout, size_addr, ui_left, "addr", _("Where")); + + if (pops == NULL) + { + const struct probe_ops *po; + int ix; + + /* We have to generate the table header for each new probe type that we + will print. */ + for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix) + gen_ui_out_table_header_info (probes, po); + } + else + gen_ui_out_table_header_info (probes, pops); + + ui_out_table_header (current_uiout, size_objname, ui_left, "object", + _("Object")); + ui_out_table_body (current_uiout); + + for (i = 0; VEC_iterate (probe_p, probes, i, probe); ++i) + { + struct cleanup *inner; + + inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe"); + + ui_out_field_string (current_uiout, "provider", probe->provider); + ui_out_field_string (current_uiout, "name", probe->name); + ui_out_field_core_addr (current_uiout, "addr", + get_objfile_arch (probe->objfile), + probe->address); + + if (pops == NULL) + { + const struct probe_ops *po; + int ix; + + for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); + ++ix) + if (probe->pops == po) + print_ui_out_info (probe); + } + else + print_ui_out_info (probe); + + ui_out_field_string (current_uiout, "object", probe->objfile->name); + ui_out_text (current_uiout, "\n"); + + do_cleanups (inner); + } + + any_found = !VEC_empty (probe_p, probes); + do_cleanups (cleanup); + + if (!any_found) + ui_out_message (current_uiout, 0, _("No probes matched.\n")); +} + +/* Implementation of the `info probes' command. */ + +static void +info_probes_command (char *arg, int from_tty) +{ + info_probes_for_ops (arg, from_tty, NULL); +} + +/* See comments in probe.h. */ + +struct value * +probe_safe_evaluate_at_pc (struct frame_info *frame, unsigned n) +{ + struct probe *probe; + const struct sym_probe_fns *probe_fns; + unsigned n_args; + + probe = find_probe_by_pc (get_frame_pc (frame)); + if (!probe) + return NULL; + + gdb_assert (probe->objfile != NULL); + gdb_assert (probe->objfile->sf != NULL); + gdb_assert (probe->objfile->sf->sym_probe_fns != NULL); + + probe_fns = probe->objfile->sf->sym_probe_fns; + n_args = probe_fns->sym_get_probe_argument_count (probe); + + if (n >= n_args) + return NULL; + + return probe_fns->sym_evaluate_probe_argument (probe, n); +} + +/* See comment in probe.h. */ + +const struct probe_ops * +probe_linespec_to_ops (const char **linespecp) +{ + int ix; + const struct probe_ops *probe_ops; + + for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, probe_ops); ix++) + if (probe_ops->is_linespec (linespecp)) + return probe_ops; + + return NULL; +} + +/* See comment in probe.h. */ + +int +probe_is_linespec_by_keyword (const char **linespecp, const char *const *keywords) +{ + const char *s = *linespecp; + const char *const *csp; + + for (csp = keywords; *csp; csp++) + { + const char *keyword = *csp; + size_t len = strlen (keyword); + + if (strncmp (s, keyword, len) == 0 && isspace (s[len])) + { + *linespecp += len + 1; + return 1; + } + } + + return 0; +} + +/* Implementation of `is_linespec' method for `struct probe_ops'. */ + +static int +probe_any_is_linespec (const char **linespecp) +{ + static const char *const keywords[] = { "-p", "-probe", NULL }; + + return probe_is_linespec_by_keyword (linespecp, keywords); +} + +/* Dummy method used for `probe_ops_any'. */ + +static void +probe_any_get_probes (VEC (probe_p) **probesp, struct objfile *objfile) +{ + /* No probes can be provided by this dummy backend. */ +} + +/* Operations associated with a generic probe. */ + +const struct probe_ops probe_ops_any = +{ + probe_any_is_linespec, + probe_any_get_probes, +}; + +/* See comments in probe.h. */ + +struct cmd_list_element ** +info_probes_cmdlist_get (void) +{ + static struct cmd_list_element *info_probes_cmdlist; + + if (info_probes_cmdlist == NULL) + add_prefix_cmd ("probes", class_info, info_probes_command, + _("\ +Show available static probes.\n\ +Usage: info probes [all|TYPE [ARGS]]\n\ +TYPE specifies the type of the probe, and can be one of the following:\n\ + - stap\n\ +If you specify TYPE, there may be additional arguments needed by the\n\ +subcommand.\n\ +If you do not specify any argument, or specify `all', then the command\n\ +will show information about all types of probes."), + &info_probes_cmdlist, "info probes ", + 0/*allow-unknown*/, &infolist); + + return &info_probes_cmdlist; +} + +VEC (probe_ops_cp) *all_probe_ops; + +void _initialize_probe (void); + +void +_initialize_probe (void) +{ + VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any); + + add_cmd ("all", class_info, info_probes_command, + _("\ +Show information about all type of probes."), + info_probes_cmdlist_get ()); +} diff --git a/contrib/gdb-7/gdb/probe.h b/contrib/gdb-7/gdb/probe.h new file mode 100644 index 0000000000..be1faa432e --- /dev/null +++ b/contrib/gdb-7/gdb/probe.h @@ -0,0 +1,225 @@ +/* Generic SDT probe support for GDB. + + Copyright (C) 2012-2013 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 (PROBE_H) +#define PROBE_H 1 + +#include "gdb_vecs.h" + +/* Definition of a vector of probes. */ + +typedef struct probe *probe_p; +DEF_VEC_P (probe_p); + +struct linespec_result; + +/* Structure useful for passing the header names in the method + `gen_ui_out_table_header'. */ + +struct info_probe_column + { + /* The internal name of the field. This string cannot be capitalized nor + localized, e.g., "extra_field". */ + + const char *field_name; + + /* The field name to be printed in the `info probes' command. This + string can be capitalized and localized, e.g., _("Extra Field"). */ + const char *print_name; + }; + +typedef struct info_probe_column info_probe_column_s; +DEF_VEC_O (info_probe_column_s); + +/* Operations associated with a probe. */ + +struct probe_ops + { + /* Method responsible for verifying if LINESPECP is a valid linespec for + a probe breakpoint. It should return 1 if it is, or zero if it is not. + It also should update LINESPECP in order to discard the breakpoint + option associated with this linespec. For example, if the option is + `-probe', and the LINESPECP is `-probe abc', the function should + return 1 and set LINESPECP to `abc'. */ + + int (*is_linespec) (const char **linespecp); + + /* Function that should fill PROBES with known probes from OBJFILE. */ + + void (*get_probes) (VEC (probe_p) **probes, struct objfile *objfile); + + /* Function used to relocate addresses from PROBE according to some DELTA + provided. */ + + void (*relocate) (struct probe *probe, CORE_ADDR delta); + + /* Return the number of arguments of PROBE. */ + + unsigned (*get_probe_argument_count) (struct probe *probe); + + /* Evaluate the Nth argument from the PROBE, returning a value + corresponding to it. The argument number is represented N. */ + + struct value *(*evaluate_probe_argument) (struct probe *probe, + unsigned n); + + /* Compile the Nth argument of the PROBE to an agent expression. + The argument number is represented by N. */ + + void (*compile_to_ax) (struct probe *probe, struct agent_expr *aexpr, + struct axs_value *axs_value, unsigned n); + + /* Set the semaphore associated with the PROBE. This function only makes + sense if the probe has a concept of semaphore associated to a + probe. */ + + void (*set_semaphore) (struct probe *probe, struct gdbarch *gdbarch); + + /* Clear the semaphore associated with the PROBE. This function only + makes sense if the probe has a concept of semaphore associated to + a probe. */ + + void (*clear_semaphore) (struct probe *probe, struct gdbarch *gdbarch); + + /* Function called to destroy PROBE's specific data. This function + shall not free PROBE itself. */ + + void (*destroy) (struct probe *probe); + + /* Function responsible for providing the extra fields that will be + printed in the `info probes' command. It should fill HEADS + with whatever extra fields it needs. If the backend doesn't need + to print extra fields, it can set this method to NULL. */ + + void (*gen_info_probes_table_header) (VEC (info_probe_column_s) **heads); + + /* Function that will fill VALUES with the values of the extra fields + to be printed for PROBE. If the backend implements the + `gen_ui_out_table_header' method, then it should implement + this method as well. The backend should also guarantee that the + order and the number of values in the vector is exactly the same + as the order of the extra fields provided in the method + `gen_ui_out_table_header'. If a certain field is to be skipped + when printing the information, you can push a NULL value in that + position in the vector. */ + + void (*gen_info_probes_table_values) (struct probe *probe, + VEC (const_char_ptr) **values); + }; + +/* Definition of a vector of probe_ops. */ + +typedef const struct probe_ops *probe_ops_cp; +DEF_VEC_P (probe_ops_cp); +extern VEC (probe_ops_cp) *all_probe_ops; + +/* The probe_ops associated with the generic probe. */ + +extern const struct probe_ops probe_ops_any; + +/* Helper function that, given KEYWORDS, iterate over it trying to match + each keyword with LINESPECP. If it succeeds, it updates the LINESPECP + pointer and returns 1. Otherwise, nothing is done to LINESPECP and zero + is returned. */ + +extern int probe_is_linespec_by_keyword (const char **linespecp, + const char *const *keywords); + +/* Return specific PROBE_OPS * matching *LINESPECP and possibly updating + *LINESPECP to skip its "-probe-type " prefix. Return &probe_ops_any if + *LINESPECP matches "-probe ", that is any unspecific probe. Return NULL if + *LINESPECP is not identified as any known probe type, *LINESPECP is not + modified in such case. */ + +extern const struct probe_ops *probe_linespec_to_ops (const char **linespecp); + +/* The probe itself. The struct contains generic information about the + probe, and then some specific information which should be stored in + the `probe_info' field. */ + +struct probe + { + /* The operations associated with this probe. */ + const struct probe_ops *pops; + + /* The objfile which contains this probe. Even if the probe is also + present in a separate debug objfile, this variable always points to + the non-separate debug objfile. */ + struct objfile *objfile; + + /* The name of the probe. */ + const char *name; + + /* The provider of the probe. It generally defaults to the name of + the objfile which contains the probe. */ + const char *provider; + + /* The address where the probe is inserted. */ + CORE_ADDR address; + }; + +/* A helper for linespec that decodes a probe specification. It returns a + symtabs_and_lines object and updates *ARGPTR or throws an error. The + argument PTYPE specifies the type of the probe(s) to be parsed. */ + +extern struct symtabs_and_lines parse_probes (char **argptr, + struct linespec_result *canon); + +/* Helper function to register the proper probe_ops to a newly created probe. + This function is mainly called from `sym_get_probes'. */ + +extern void register_probe_ops (struct probe *probe); + +/* Given a PC, find an associated probe with type PTYPE. If a probe is + found, return it. If no probe is found, return NULL. */ + +extern struct probe *find_probe_by_pc (CORE_ADDR pc); + +/* Search OBJFILE for a probe with the given PROVIDER, NAME and PTYPE. + Return a VEC of all probes that were found. If no matching probe + is found, return NULL. The caller must free the VEC. */ + +extern VEC (probe_p) *find_probes_in_objfile (struct objfile *objfile, + const char *provider, + const char *name); + +/* Generate a `info probes' command output for probe_ops represented by + POPS. If POPS is NULL it considers any probes types. It is a helper + function that can be used by the probe backends to print their + `info probe TYPE'. */ + +extern void info_probes_for_ops (char *arg, int from_tty, + const struct probe_ops *pops); + +/* Return the `cmd_list_element' associated with the `info probes' command, + or create a new one if it doesn't exist. Helper function that serves the + purpose of avoiding the case of a backend using the `cmd_list_element' + associated with `info probes', without having it registered yet. */ + +extern struct cmd_list_element **info_probes_cmdlist_get (void); + +/* A convenience function that finds a probe at the PC in FRAME and + evaluates argument N, with 0 <= N < number_of_args. If there is no + probe at that location, or if the probe does not have enough arguments, + this returns NULL. */ + +extern struct value *probe_safe_evaluate_at_pc (struct frame_info *frame, + unsigned n); + +#endif /* !defined (PROBE_H) */ diff --git a/contrib/gdb-7/gdb/proc-service.list b/contrib/gdb-7/gdb/proc-service.list index 5660e9e8ae..4f99d57493 100644 --- a/contrib/gdb-7/gdb/proc-service.list +++ b/contrib/gdb-7/gdb/proc-service.list @@ -1,6 +1,6 @@ /* -Wl,--dynamic-list symbols exported for libthread_db. - Copyright (C) 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/progspace.c b/contrib/gdb-7/gdb/progspace.c index 7175fa6ab1..52460ab84f 100644 --- a/contrib/gdb-7/gdb/progspace.c +++ b/contrib/gdb-7/gdb/progspace.c @@ -1,6 +1,6 @@ /* Program and address space management, for GDB, the GNU debugger. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -37,10 +37,13 @@ struct program_space *current_program_space; /* The last address space number assigned. */ static int highest_address_space_num; -/* Prototypes for local functions */ + + +/* Keep a registry of per-program_space data-pointers required by other GDB + modules. */ + +DEFINE_REGISTRY (program_space, REGISTRY_ACCESS_FIELD) -static void program_space_alloc_data (struct program_space *); -static void program_space_free_data (struct program_space *); /* An address space. Currently this is not used for much other than @@ -72,7 +75,7 @@ new_address_space (void) struct address_space * maybe_new_address_space (void) { - int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch); + int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch ()); if (shared_aspace) { @@ -145,10 +148,11 @@ release_program_space (struct program_space *pspace) no_shared_libraries (NULL, 0); exec_close (); free_all_objfiles (); - if (!gdbarch_has_shared_address_space (target_gdbarch)) + if (!gdbarch_has_shared_address_space (target_gdbarch ())) free_address_space (pspace->aspace); resize_section_table (&pspace->target_sections, -resize_section_table (&pspace->target_sections, 0)); + clear_program_space_solib_cache (pspace); /* Discard any data modules have associated with the PSPACE. */ program_space_free_data (pspace); xfree (pspace); @@ -192,8 +196,8 @@ clone_program_space (struct program_space *dest, struct program_space *src) set_current_program_space (dest); - if (src->ebfd != NULL) - exec_file_attach (bfd_get_filename (src->ebfd), 0); + if (src->pspace_exec_filename != NULL) + exec_file_attach (src->pspace_exec_filename, 0); if (src->symfile_object_file != NULL) symbol_file_add_main (src->symfile_object_file->name, 0); @@ -332,9 +336,8 @@ print_program_space (struct ui_out *uiout, int requested) ui_out_field_int (uiout, "id", pspace->num); - if (pspace->ebfd) - ui_out_field_string (uiout, "exec", - bfd_get_filename (pspace->ebfd)); + if (pspace->pspace_exec_filename) + ui_out_field_string (uiout, "exec", pspace->pspace_exec_filename); else ui_out_field_skip (uiout, "exec"); @@ -428,7 +431,7 @@ number_of_program_spaces (void) void update_address_spaces (void) { - int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch); + int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch ()); struct program_space *pspace; struct inferior *inf; @@ -450,7 +453,7 @@ update_address_spaces (void) } for (inf = inferior_list; inf; inf = inf->next) - if (gdbarch_has_global_solist (target_gdbarch)) + if (gdbarch_has_global_solist (target_gdbarch ())) inf->aspace = maybe_new_address_space (); else inf->aspace = inf->pspace->aspace; @@ -503,104 +506,15 @@ switch_to_program_space_and_thread (struct program_space *pspace) -/* Keep a registry of per-program_space data-pointers required by other GDB - modules. */ - -struct program_space_data -{ - unsigned index; - void (*cleanup) (struct program_space *, void *); -}; - -struct program_space_data_registration -{ - struct program_space_data *data; - struct program_space_data_registration *next; -}; - -struct program_space_data_registry -{ - struct program_space_data_registration *registrations; - unsigned num_registrations; -}; - -static struct program_space_data_registry program_space_data_registry - = { NULL, 0 }; - -const struct program_space_data * -register_program_space_data_with_cleanup - (void (*cleanup) (struct program_space *, void *)) -{ - struct program_space_data_registration **curr; - - /* Append new registration. */ - for (curr = &program_space_data_registry.registrations; - *curr != NULL; curr = &(*curr)->next); - - *curr = XMALLOC (struct program_space_data_registration); - (*curr)->next = NULL; - (*curr)->data = XMALLOC (struct program_space_data); - (*curr)->data->index = program_space_data_registry.num_registrations++; - (*curr)->data->cleanup = cleanup; - - return (*curr)->data; -} - -const struct program_space_data * -register_program_space_data (void) -{ - return register_program_space_data_with_cleanup (NULL); -} - -static void -program_space_alloc_data (struct program_space *pspace) -{ - gdb_assert (pspace->data == NULL); - pspace->num_data = program_space_data_registry.num_registrations; - pspace->data = XCALLOC (pspace->num_data, void *); -} - -static void -program_space_free_data (struct program_space *pspace) -{ - gdb_assert (pspace->data != NULL); - clear_program_space_data (pspace); - xfree (pspace->data); - pspace->data = NULL; -} - -void -clear_program_space_data (struct program_space *pspace) -{ - struct program_space_data_registration *registration; - int i; - - gdb_assert (pspace->data != NULL); - - for (registration = program_space_data_registry.registrations, i = 0; - i < pspace->num_data; - registration = registration->next, i++) - if (pspace->data[i] != NULL && registration->data->cleanup) - registration->data->cleanup (pspace, pspace->data[i]); - - memset (pspace->data, 0, pspace->num_data * sizeof (void *)); -} +/* See progspace.h. */ void -set_program_space_data (struct program_space *pspace, - const struct program_space_data *data, - void *value) +clear_program_space_solib_cache (struct program_space *pspace) { - gdb_assert (data->index < pspace->num_data); - pspace->data[data->index] = value; -} + VEC_free (so_list_ptr, pspace->added_solibs); -void * -program_space_data (struct program_space *pspace, - const struct program_space_data *data) -{ - gdb_assert (data->index < pspace->num_data); - return pspace->data[data->index]; + free_char_ptr_vec (pspace->deleted_solibs); + pspace->deleted_solibs = NULL; } diff --git a/contrib/gdb-7/gdb/progspace.h b/contrib/gdb-7/gdb/progspace.h index 9822f70b70..f24a5697d3 100644 --- a/contrib/gdb-7/gdb/progspace.h +++ b/contrib/gdb-7/gdb/progspace.h @@ -1,6 +1,6 @@ /* Program and address space management, for GDB, the GNU debugger. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -23,6 +23,8 @@ #include "target.h" #include "vec.h" +#include "gdb_vecs.h" +#include "registry.h" struct target_ops; struct bfd; @@ -32,6 +34,9 @@ struct exec; struct address_space; struct program_space_data; +typedef struct so_list *so_list_ptr; +DEF_VEC_P (so_list_ptr); + /* A program space represents a symbolic view of an address space. Roughly speaking, it holds all the data associated with a non-running-yet program (main executable, main symbols), and when @@ -143,6 +148,10 @@ struct program_space bfd *ebfd; /* The last-modified time, from when the exec was brought in. */ long ebfd_mtime; + /* Similar to bfd_get_filename (exec_bfd) but in original form given + by user, without symbolic links and pathname resolved. + It needs to be freed by xfree. It is not NULL iff EBFD is not NULL. */ + char *pspace_exec_filename; /* The address space attached to this program space. More than one program space may be bound to the same address space. In the @@ -188,9 +197,16 @@ struct program_space /* Number of calls to solib_add. */ unsigned solib_add_generation; + /* When an solib is added, it is also added to this vector. This + is so we can properly report solib changes to the user. */ + VEC (so_list_ptr) *added_solibs; + + /* When an solib is removed, its name is added to this vector. + This is so we can properly report solib changes to the user. */ + VEC (char_ptr) *deleted_solibs; + /* Per pspace data-pointers required by other GDB modules. */ - void **data; - unsigned num_data; + REGISTRY_FIELDS; }; /* The object file that the main symbol table was loaded from (e.g. the @@ -278,17 +294,14 @@ extern void update_address_spaces (void); anymore. */ extern void prune_program_spaces (void); +/* Reset saved solib data at the start of an solib event. This lets + us properly collect the data when calling solib_add, so it can then + later be printed. */ +extern void clear_program_space_solib_cache (struct program_space *); + /* Keep a registry of per-pspace data-pointers required by other GDB modules. */ -extern const struct program_space_data *register_program_space_data (void); -extern const struct program_space_data *register_program_space_data_with_cleanup - (void (*cleanup) (struct program_space *, void *)); -extern void clear_program_space_data (struct program_space *pspace); -extern void set_program_space_data (struct program_space *pspace, - const struct program_space_data *data, - void *value); -extern void *program_space_data (struct program_space *pspace, - const struct program_space_data *data); +DECLARE_REGISTRY (program_space); #endif diff --git a/contrib/gdb-7/gdb/prologue-value.c b/contrib/gdb-7/gdb/prologue-value.c index e84a103bad..6c686181f0 100644 --- a/contrib/gdb-7/gdb/prologue-value.c +++ b/contrib/gdb-7/gdb/prologue-value.c @@ -1,5 +1,5 @@ /* Prologue value handling for GDB. - Copyright 2003-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/prologue-value.h b/contrib/gdb-7/gdb/prologue-value.h index 93dab10f60..b8ed813140 100644 --- a/contrib/gdb-7/gdb/prologue-value.h +++ b/contrib/gdb-7/gdb/prologue-value.h @@ -1,5 +1,5 @@ /* Interface to prologue value handling for GDB. - Copyright 2003-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/psympriv.h b/contrib/gdb-7/gdb/psympriv.h index 7cf9260ba0..cd8d06f6ec 100644 --- a/contrib/gdb-7/gdb/psympriv.h +++ b/contrib/gdb-7/gdb/psympriv.h @@ -1,6 +1,6 @@ /* Private partial symbol table definitions. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -54,6 +54,17 @@ struct partial_symbol #define PSYMBOL_DOMAIN(psymbol) (psymbol)->domain #define PSYMBOL_CLASS(psymbol) (psymbol)->aclass +/* A convenience enum to give names to some constants used when + searching psymtabs. This is internal to psymtab and should not be + used elsewhere. */ + +enum psymtab_search_status + { + PST_NOT_SEARCHED, + PST_SEARCHED_AND_FOUND, + PST_SEARCHED_AND_NOT_FOUND + }; + /* Each source file that has not been fully read in is represented by a partial_symtab. This contains the information on where in the executable the debugging symbols for a specific file are, and a @@ -71,7 +82,9 @@ struct partial_symtab struct partial_symtab *next; - /* Name of the source file which this partial_symtab defines. */ + /* Name of the source file which this partial_symtab defines, + or if the psymtab is anonymous then a descriptive name for + debugging purposes, or "". It must not be NULL. */ const char *filename; @@ -83,10 +96,6 @@ struct partial_symtab const char *dirname; - /* Information about the object file from which symbols should be read. */ - - struct objfile *objfile; - /* Set of relocation offsets to apply to each section. */ struct section_offsets *section_offsets; @@ -111,6 +120,35 @@ struct partial_symtab int number_of_dependencies; + /* If NULL, this is an ordinary partial symbol table. + + If non-NULL, this holds a single includer of this partial symbol + table, and this partial symbol table is a shared one. + + A shared psymtab is one that is referenced by multiple other + psymtabs, and which conceptually has its contents directly + included in those. + + Shared psymtabs have special semantics. When a search finds a + symbol in a shared table, we instead return one of the non-shared + tables that include this one. + + A shared psymtabs can be referred to by other shared ones. + + The psymtabs that refer to a shared psymtab will list the shared + psymtab in their 'dependencies' array. + + In DWARF terms, a shared psymtab is a DW_TAG_partial_unit; but + of course using a name based on that would be too confusing, so + "shared" was chosen instead. + + Only a single user is needed because, when expanding a shared + psymtab, we only need to expand its "canonical" non-shared user. + The choice of which one should be canonical is left to the + debuginfo reader; it can be arbitrary. */ + + struct partial_symtab *user; + /* Global symbol list. This list will be sorted after readin to improve access. Binary search will be the usual method of finding a symbol within it. globals_offset is an integer offset @@ -142,6 +180,14 @@ struct partial_symtab unsigned char psymtabs_addrmap_supported; + /* True if the name of this partial symtab is not a source file name. */ + + unsigned char anonymous; + + /* A flag that is temporarily used when searching psymtabs. */ + + ENUM_BITFIELD (psymtab_search_status) searched_flag : 2; + /* Pointer to symtab eventually allocated for this source file, 0 if !readin or if we haven't looked for the symtab after it was readin. */ @@ -150,7 +196,7 @@ struct partial_symtab /* Pointer to function which will read in the symtab corresponding to this psymtab. */ - void (*read_symtab) (struct partial_symtab *); + void (*read_symtab) (struct partial_symtab *, struct objfile *); /* Information that lets read_symtab() locate the part of the symbol table that this psymtab corresponds to. This information is private to the @@ -160,17 +206,16 @@ struct partial_symtab void *read_symtab_private; }; -extern void sort_pst_symbols (struct partial_symtab *); +extern void sort_pst_symbols (struct objfile *, struct partial_symtab *); /* Add any kind of symbol to a psymbol_allocation_list. */ -extern const -struct partial_symbol *add_psymbol_to_list (const char *, int, - int, domain_enum, - enum address_class, - struct psymbol_allocation_list *, - long, CORE_ADDR, - enum language, struct objfile *); +extern void add_psymbol_to_list (const char *, int, + int, domain_enum, + enum address_class, + struct psymbol_allocation_list *, + long, CORE_ADDR, + enum language, struct objfile *); extern void init_psymbol_list (struct objfile *, int); @@ -181,9 +226,12 @@ extern struct partial_symtab *start_psymtab_common (struct objfile *, struct partial_symbol **); extern struct partial_symtab *allocate_psymtab (const char *, - struct objfile *); + struct objfile *) + ATTRIBUTE_NONNULL (1); + +extern void discard_psymtab (struct objfile *, struct partial_symtab *); -extern void discard_psymtab (struct partial_symtab *); +extern struct cleanup *make_cleanup_discard_psymtabs (struct objfile *); /* Traverse all psymtabs in one objfile. */ diff --git a/contrib/gdb-7/gdb/psymtab.c b/contrib/gdb-7/gdb/psymtab.c index d5cfa8b22f..3075be4a16 100644 --- a/contrib/gdb-7/gdb/psymtab.c +++ b/contrib/gdb-7/gdb/psymtab.c @@ -1,6 +1,6 @@ /* Partial symbol tables. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -35,6 +35,7 @@ #include "dictionary.h" #include "language.h" #include "cp-support.h" +#include "gdbcmd.h" #ifndef DEV_TTY #define DEV_TTY "/dev/tty" @@ -45,31 +46,30 @@ struct psymbol_bcache struct bcache *bcache; }; -/* A fast way to get from a psymtab to its symtab (after the first time). */ -#define PSYMTAB_TO_SYMTAB(pst) \ - ((pst) -> symtab != NULL ? (pst) -> symtab : psymtab_to_symtab (pst)) - -static struct partial_symbol *match_partial_symbol (struct partial_symtab *, +static struct partial_symbol *match_partial_symbol (struct objfile *, + struct partial_symtab *, int, const char *, domain_enum, symbol_compare_ftype *, symbol_compare_ftype *); -static struct partial_symbol *lookup_partial_symbol (struct partial_symtab *, +static struct partial_symbol *lookup_partial_symbol (struct objfile *, + struct partial_symtab *, const char *, int, domain_enum); -static char *psymtab_to_fullname (struct partial_symtab *ps); +static const char *psymtab_to_fullname (struct partial_symtab *ps); -static struct partial_symbol *find_pc_sect_psymbol (struct partial_symtab *, +static struct partial_symbol *find_pc_sect_psymbol (struct objfile *, + struct partial_symtab *, CORE_ADDR, struct obj_section *); -static struct partial_symbol *fixup_psymbol_section (struct partial_symbol - *psym, - struct objfile *objfile); +static void fixup_psymbol_section (struct partial_symbol *psym, + struct objfile *objfile); -static struct symtab *psymtab_to_symtab (struct partial_symtab *pst); +static struct symtab *psymtab_to_symtab (struct objfile *objfile, + struct partial_symtab *pst); /* Ensure that the partial symbols for OBJFILE have been loaded. This function always returns its argument, as a convenience. */ @@ -131,7 +131,6 @@ require_partial_symbols (struct objfile *objfile, int verbose) static int partial_map_expand_apply (struct objfile *objfile, const char *name, - const char *full_path, const char *real_path, struct partial_symtab *pst, int (*callback) (struct symtab *, void *), @@ -139,15 +138,19 @@ partial_map_expand_apply (struct objfile *objfile, { struct symtab *last_made = objfile->symtabs; + /* Shared psymtabs should never be seen here. Instead they should + be handled properly by the caller. */ + gdb_assert (pst->user == NULL); + /* Don't visit already-expanded psymtabs. */ if (pst->readin) return 0; /* This may expand more than one symtab, and we want to iterate over all of them. */ - psymtab_to_symtab (pst); + psymtab_to_symtab (objfile, pst); - return iterate_over_some_symtabs (name, full_path, real_path, callback, data, + return iterate_over_some_symtabs (name, real_path, callback, data, objfile->symtabs, last_made); } @@ -156,7 +159,6 @@ partial_map_expand_apply (struct objfile *objfile, static int partial_map_symtabs_matching_filename (struct objfile *objfile, const char *name, - const char *full_path, const char *real_path, int (*callback) (struct symtab *, void *), @@ -167,9 +169,18 @@ partial_map_symtabs_matching_filename (struct objfile *objfile, ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst) { - if (FILENAME_CMP (name, pst->filename) == 0) + /* We can skip shared psymtabs here, because any file name will be + attached to the unshared psymtab. */ + if (pst->user != NULL) + continue; + + /* Anonymous psymtabs don't have a file name. */ + if (pst->anonymous) + continue; + + if (compare_filenames_for_search (pst->filename, name)) { - if (partial_map_expand_apply (objfile, name, full_path, real_path, + if (partial_map_expand_apply (objfile, name, real_path, pst, callback, data)) return 1; } @@ -180,49 +191,28 @@ partial_map_symtabs_matching_filename (struct objfile *objfile, && FILENAME_CMP (name_basename, lbasename (pst->filename)) != 0) continue; - /* If the user gave us an absolute path, try to find the file in - this symtab and use its absolute path. */ - if (full_path != NULL) + if (compare_filenames_for_search (psymtab_to_fullname (pst), name)) { - psymtab_to_fullname (pst); - if (pst->fullname != NULL - && FILENAME_CMP (full_path, pst->fullname) == 0) - { - if (partial_map_expand_apply (objfile, name, full_path, real_path, - pst, callback, data)) - return 1; - } + if (partial_map_expand_apply (objfile, name, real_path, + pst, callback, data)) + return 1; } + /* If the user gave us an absolute path, try to find the file in + this symtab and use its absolute path. */ if (real_path != NULL) { - char *rp = NULL; - psymtab_to_fullname (pst); - if (pst->fullname != NULL) - { - rp = gdb_realpath (pst->fullname); - make_cleanup (xfree, rp); - } - if (rp != NULL && FILENAME_CMP (real_path, rp) == 0) + gdb_assert (IS_ABSOLUTE_PATH (real_path)); + gdb_assert (IS_ABSOLUTE_PATH (name)); + if (filename_cmp (psymtab_to_fullname (pst), real_path) == 0) { - if (partial_map_expand_apply (objfile, name, full_path, real_path, + if (partial_map_expand_apply (objfile, name, real_path, pst, callback, data)) return 1; } } } - /* Now, search for a matching tail (only if name doesn't have any dirs). */ - - if (name_basename == name) - ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst) - { - if (FILENAME_CMP (lbasename (pst->filename), name) == 0) - if (partial_map_expand_apply (objfile, name, full_path, real_path, pst, - callback, data)) - return 1; - } - return 0; } @@ -230,11 +220,11 @@ partial_map_symtabs_matching_filename (struct objfile *objfile, We may find a different psymtab than PST. See FIND_PC_SECT_PSYMTAB. */ static struct partial_symtab * -find_pc_sect_psymtab_closer (CORE_ADDR pc, struct obj_section *section, +find_pc_sect_psymtab_closer (struct objfile *objfile, + CORE_ADDR pc, struct obj_section *section, struct partial_symtab *pst, struct minimal_symbol *msymbol) { - struct objfile *objfile = pst->objfile; struct partial_symtab *tpst; struct partial_symtab *best_pst = pst; CORE_ADDR best_addr = pst->textlow; @@ -270,7 +260,7 @@ find_pc_sect_psymtab_closer (CORE_ADDR pc, struct obj_section *section, corresponding msymbol, which is not necessarily true; the debug info might be much richer than the object's symbol table. */ - p = find_pc_sect_psymbol (tpst, pc, section); + p = find_pc_sect_psymbol (objfile, tpst, pc, section); if (p != NULL && SYMBOL_VALUE_ADDRESS (p) == SYMBOL_VALUE_ADDRESS (msymbol)) @@ -335,7 +325,7 @@ find_pc_sect_psymtab (struct objfile *objfile, CORE_ADDR pc, corresponding msymbol, which is not necessarily true; the debug info might be much richer than the object's symbol table. */ - p = find_pc_sect_psymbol (pst, pc, section); + p = find_pc_sect_psymbol (objfile, pst, pc, section); if (!p || SYMBOL_VALUE_ADDRESS (p) != SYMBOL_VALUE_ADDRESS (msymbol)) @@ -369,7 +359,8 @@ find_pc_sect_psymtab (struct objfile *objfile, CORE_ADDR pc, { struct partial_symtab *best_pst; - best_pst = find_pc_sect_psymtab_closer (pc, section, pst, msymbol); + best_pst = find_pc_sect_psymtab_closer (objfile, pc, section, pst, + msymbol); if (best_pst != NULL) return best_pst; } @@ -393,8 +384,9 @@ find_pc_sect_symtab_from_partial (struct objfile *objfile, continue, so let's not. */ warning (_("\ (Internal error: pc %s in read in psymtab, but not in symtab.)\n"), - paddress (get_objfile_arch (ps->objfile), pc)); - return PSYMTAB_TO_SYMTAB (ps); + paddress (get_objfile_arch (objfile), pc)); + psymtab_to_symtab (objfile, ps); + return ps->symtab; } return NULL; } @@ -403,7 +395,8 @@ find_pc_sect_symtab_from_partial (struct objfile *objfile, Return 0 if none. */ static struct partial_symbol * -find_pc_sect_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc, +find_pc_sect_psymbol (struct objfile *objfile, + struct partial_symtab *psymtab, CORE_ADDR pc, struct obj_section *section) { struct partial_symbol *best = NULL, *p, **pp; @@ -417,8 +410,8 @@ find_pc_sect_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc, /* Search the global symbols as well as the static symbols, so that find_pc_partial_function doesn't use a minimal symbol and thus cache a bad endaddr. */ - for (pp = psymtab->objfile->global_psymbols.list + psymtab->globals_offset; - (pp - (psymtab->objfile->global_psymbols.list + psymtab->globals_offset) + for (pp = objfile->global_psymbols.list + psymtab->globals_offset; + (pp - (objfile->global_psymbols.list + psymtab->globals_offset) < psymtab->n_global_syms); pp++) { @@ -432,7 +425,7 @@ find_pc_sect_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc, { if (section) /* Match on a specific section. */ { - fixup_psymbol_section (p, psymtab->objfile); + fixup_psymbol_section (p, objfile); if (!matching_obj_sections (SYMBOL_OBJ_SECTION (p), section)) continue; } @@ -441,8 +434,8 @@ find_pc_sect_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc, } } - for (pp = psymtab->objfile->static_psymbols.list + psymtab->statics_offset; - (pp - (psymtab->objfile->static_psymbols.list + psymtab->statics_offset) + for (pp = objfile->static_psymbols.list + psymtab->statics_offset; + (pp - (objfile->static_psymbols.list + psymtab->statics_offset) < psymtab->n_static_syms); pp++) { @@ -456,7 +449,7 @@ find_pc_sect_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc, { if (section) /* Match on a specific section. */ { - fixup_psymbol_section (p, psymtab->objfile); + fixup_psymbol_section (p, objfile); if (!matching_obj_sections (SYMBOL_OBJ_SECTION (p), section)) continue; } @@ -468,16 +461,13 @@ find_pc_sect_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc, return best; } -static struct partial_symbol * +static void fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile) { CORE_ADDR addr; - if (!psym) - return NULL; - - if (SYMBOL_OBJ_SECTION (psym)) - return psym; + if (psym == NULL || SYMBOL_OBJ_SECTION (psym) != NULL) + return; gdb_assert (objfile); @@ -491,12 +481,10 @@ fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile) default: /* Nothing else will be listed in the minsyms -- no use looking it up. */ - return psym; + return; } fixup_section (&psym->ginfo, addr, objfile); - - return psym; } static struct symtab * @@ -506,13 +494,15 @@ lookup_symbol_aux_psymtabs (struct objfile *objfile, { struct partial_symtab *ps; const int psymtab_index = (block_index == GLOBAL_BLOCK ? 1 : 0); + struct symtab *stab_best = NULL; ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, ps) { - if (!ps->readin && lookup_partial_symbol (ps, name, psymtab_index, domain)) + if (!ps->readin && lookup_partial_symbol (objfile, ps, name, + psymtab_index, domain)) { struct symbol *sym = NULL; - struct symtab *stab = PSYMTAB_TO_SYMTAB (ps); + struct symtab *stab = psymtab_to_symtab (objfile, ps); /* Some caution must be observed with overloaded functions and methods, since the psymtab will not contain any overload @@ -526,13 +516,18 @@ lookup_symbol_aux_psymtabs (struct objfile *objfile, } if (sym && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0) - return stab; + { + if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) + return stab; + + stab_best = stab; + } /* Keep looking through other psymtabs. */ } } - return NULL; + return stab_best; } /* Look in PST for a symbol in DOMAIN whose name matches NAME. Search @@ -544,7 +539,8 @@ lookup_symbol_aux_psymtabs (struct objfile *objfile, with MATCH. Returns the symbol, if found, and otherwise NULL. */ static struct partial_symbol * -match_partial_symbol (struct partial_symtab *pst, int global, +match_partial_symbol (struct objfile *objfile, + struct partial_symtab *pst, int global, const char *name, domain_enum domain, symbol_compare_ftype *match, symbol_compare_ftype *ordered_compare) @@ -557,8 +553,8 @@ match_partial_symbol (struct partial_symtab *pst, int global, if (length == 0) return NULL; start = (global ? - pst->objfile->global_psymbols.list + pst->globals_offset : - pst->objfile->static_psymbols.list + pst->statics_offset); + objfile->global_psymbols.list + pst->globals_offset : + objfile->static_psymbols.list + pst->statics_offset); if (global && ordered_compare) /* Can use a binary search. */ { @@ -614,15 +610,6 @@ match_partial_symbol (struct partial_symtab *pst, int global, return NULL; } -static void -pre_expand_symtabs_matching_psymtabs (struct objfile *objfile, - enum block_enum block_kind, - const char *name, - domain_enum domain) -{ - /* Nothing. */ -} - /* Returns the name used to search psymtabs. Unlike symtabs, psymtabs do not contain any method/function instance information (since this would force reading type information while reading psymtabs). Therefore, @@ -660,7 +647,8 @@ psymtab_search_name (const char *name) Check the global symbols if GLOBAL, the static symbols if not. */ static struct partial_symbol * -lookup_partial_symbol (struct partial_symtab *pst, const char *name, +lookup_partial_symbol (struct objfile *objfile, + struct partial_symtab *pst, const char *name, int global, domain_enum domain) { struct partial_symbol **start, **psym; @@ -678,8 +666,8 @@ lookup_partial_symbol (struct partial_symtab *pst, const char *name, search_name = psymtab_search_name (name); cleanup = make_cleanup (xfree, search_name); start = (global ? - pst->objfile->global_psymbols.list + pst->globals_offset : - pst->objfile->static_psymbols.list + pst->statics_offset); + objfile->global_psymbols.list + pst->globals_offset : + objfile->static_psymbols.list + pst->statics_offset); if (global) /* This means we can use a binary search. */ { @@ -761,13 +749,16 @@ lookup_partial_symbol (struct partial_symtab *pst, const char *name, } /* Get the symbol table that corresponds to a partial_symtab. - This is fast after the first time you do it. In fact, there - is an even faster macro PSYMTAB_TO_SYMTAB that does the fast - case inline. */ + This is fast after the first time you do it. */ static struct symtab * -psymtab_to_symtab (struct partial_symtab *pst) +psymtab_to_symtab (struct objfile *objfile, struct partial_symtab *pst) { + /* If it is a shared psymtab, find an unshared psymtab that includes + it. Any such psymtab will do. */ + while (pst->user != NULL) + pst = pst->user; + /* If it's been looked up before, return it. */ if (pst->symtab) return pst->symtab; @@ -777,7 +768,7 @@ psymtab_to_symtab (struct partial_symtab *pst) { struct cleanup *back_to = increment_reading_symtab (); - (*pst->read_symtab) (pst); + (*pst->read_symtab) (pst, objfile); do_cleanups (back_to); } @@ -843,7 +834,7 @@ find_last_source_symtab_from_partial (struct objfile *ofp) "readin pst found and no symtabs.")); } else - return PSYMTAB_TO_SYMTAB (cs_pst); + return psymtab_to_symtab (ofp, cs_pst); } return NULL; } @@ -871,6 +862,7 @@ print_partial_symbols (struct gdbarch *gdbarch, fprintf_filtered (outfile, " %s partial symbols:\n", what); while (count-- > 0) { + QUIT; fprintf_filtered (outfile, " `%s'", SYMBOL_LINKAGE_NAME (*p)); if (SYMBOL_DEMANGLED_NAME (*p) != NULL) { @@ -960,8 +952,16 @@ dump_psymtab (struct objfile *objfile, struct partial_symtab *psymtab, struct gdbarch *gdbarch = get_objfile_arch (objfile); int i; - fprintf_filtered (outfile, "\nPartial symtab for source file %s ", - psymtab->filename); + if (psymtab->anonymous) + { + fprintf_filtered (outfile, "\nAnonymous partial symtab (%s) ", + psymtab->filename); + } + else + { + fprintf_filtered (outfile, "\nPartial symtab for source file %s ", + psymtab->filename); + } fprintf_filtered (outfile, "(object "); gdb_print_host_address (psymtab, outfile); fprintf_filtered (outfile, ")\n\n"); @@ -981,7 +981,7 @@ dump_psymtab (struct objfile *objfile, struct partial_symtab *psymtab, } fprintf_filtered (outfile, " Relocate symbols by "); - for (i = 0; i < psymtab->objfile->num_sections; ++i) + for (i = 0; i < objfile->num_sections; ++i) { if (i != 0) fprintf_filtered (outfile, ", "); @@ -1008,6 +1008,12 @@ dump_psymtab (struct objfile *objfile, struct partial_symtab *psymtab, fprintf_filtered (outfile, " %s\n", psymtab->dependencies[i]->filename); } + if (psymtab->user != NULL) + { + fprintf_filtered (outfile, " Shared partial symtab with user "); + gdb_print_host_address (psymtab->user, outfile); + fprintf_filtered (outfile, "\n"); + } if (psymtab->n_global_syms > 0) { print_partial_symbols (gdbarch, @@ -1056,10 +1062,6 @@ dump_psymtabs_for_objfile (struct objfile *objfile) psymtab->filename); gdb_print_host_address (psymtab, gdb_stdout); printf_filtered (", "); - if (psymtab->objfile != objfile) - { - printf_filtered ("NOT ON CHAIN! "); - } wrap_here (" "); } printf_filtered ("\n\n"); @@ -1079,11 +1081,11 @@ read_symtabs_for_function (struct objfile *objfile, const char *func_name) if (ps->readin) continue; - if ((lookup_partial_symbol (ps, func_name, 1, VAR_DOMAIN) + if ((lookup_partial_symbol (objfile, ps, func_name, 1, VAR_DOMAIN) != NULL) - || (lookup_partial_symbol (ps, func_name, 0, VAR_DOMAIN) + || (lookup_partial_symbol (objfile, ps, func_name, 0, VAR_DOMAIN) != NULL)) - psymtab_to_symtab (ps); + psymtab_to_symtab (objfile, ps); } } @@ -1094,19 +1096,27 @@ expand_partial_symbol_tables (struct objfile *objfile) ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, psymtab) { - psymtab_to_symtab (psymtab); + psymtab_to_symtab (objfile, psymtab); } } static void -read_psymtabs_with_filename (struct objfile *objfile, const char *filename) +read_psymtabs_with_fullname (struct objfile *objfile, const char *fullname) { struct partial_symtab *p; ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, p) { - if (filename_cmp (filename, p->filename) == 0) - PSYMTAB_TO_SYMTAB (p); + /* Anonymous psymtabs don't have a name of a source file. */ + if (p->anonymous) + continue; + + /* psymtab_to_fullname tries to open the file which is slow. + Don't call it if we know the basenames don't match. */ + if ((basenames_may_differ + || filename_cmp (lbasename (fullname), lbasename (p->filename)) == 0) + && filename_cmp (fullname, psymtab_to_fullname (p)) == 0) + psymtab_to_symtab (objfile, p); } } @@ -1124,6 +1134,15 @@ map_symbol_filenames_psymtab (struct objfile *objfile, if (ps->readin) continue; + /* We can skip shared psymtabs here, because any file name will be + attached to the unshared psymtab. */ + if (ps->user != NULL) + continue; + + /* Anonymous psymtabs don't have a file name. */ + if (ps->anonymous) + continue; + QUIT; if (need_fullname) fullname = psymtab_to_fullname (ps); @@ -1133,10 +1152,6 @@ map_symbol_filenames_psymtab (struct objfile *objfile, } } -int find_and_open_source (const char *filename, - const char *dirname, - char **fullname); - /* Finds the fullname that a partial_symtab represents. If this functions finds the fullname, it will save it in ps->fullname @@ -1145,29 +1160,42 @@ int find_and_open_source (const char *filename, If this function fails to find the file that this partial_symtab represents, NULL will be returned and ps->fullname will be set to NULL. */ -static char * +static const char * psymtab_to_fullname (struct partial_symtab *ps) { - int r; - - if (!ps) - return NULL; + gdb_assert (!ps->anonymous); /* Use cached copy if we have it. We rely on forget_cached_source_info being called appropriately to handle cases like the file being moved. */ - if (ps->fullname) - return ps->fullname; + if (ps->fullname == NULL) + { + int fd = find_and_open_source (ps->filename, ps->dirname, &ps->fullname); - r = find_and_open_source (ps->filename, ps->dirname, &ps->fullname); + if (fd >= 0) + close (fd); + else + { + char *fullname; + struct cleanup *back_to; - if (r >= 0) - { - close (r); - return ps->fullname; - } + /* rewrite_source_path would be applied by find_and_open_source, we + should report the pathname where GDB tried to find the file. */ - return NULL; + if (ps->dirname == NULL || IS_ABSOLUTE_PATH (ps->filename)) + fullname = xstrdup (ps->filename); + else + fullname = concat (ps->dirname, SLASH_STRING, ps->filename, NULL); + + back_to = make_cleanup (xfree, fullname); + ps->fullname = rewrite_source_path (fullname); + if (ps->fullname == NULL) + ps->fullname = xstrdup (fullname); + do_cleanups (back_to); + } + } + + return ps->fullname; } static const char * @@ -1177,7 +1205,7 @@ find_symbol_file_from_partial (struct objfile *objfile, const char *name) ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst) { - if (lookup_partial_symbol (pst, name, 1, VAR_DOMAIN)) + if (lookup_partial_symbol (objfile, pst, name, 1, VAR_DOMAIN)) return pst->filename; } return NULL; @@ -1194,11 +1222,11 @@ map_block (const char *name, domain_enum namespace, struct objfile *objfile, int (*callback) (struct block *, struct symbol *, void *), void *data, symbol_compare_ftype *match) { - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym; - for (sym = dict_iter_match_first (BLOCK_DICT (block), name, match, &iter); - sym != NULL; sym = dict_iter_match_next (name, match, &iter)) + for (sym = block_iter_match_first (block, name, match, &iter); + sym != NULL; sym = block_iter_match_next (name, match, &iter)) { if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), SYMBOL_DOMAIN (sym), namespace)) @@ -1230,10 +1258,10 @@ map_matching_symbols_psymtab (const char *name, domain_enum namespace, { QUIT; if (ps->readin - || match_partial_symbol (ps, global, name, namespace, match, + || match_partial_symbol (objfile, ps, global, name, namespace, match, ordered_compare)) { - struct symtab *s = PSYMTAB_TO_SYMTAB (ps); + struct symtab *s = psymtab_to_symtab (objfile, ps); struct block *block; if (s == NULL || !s->primary) @@ -1248,71 +1276,136 @@ map_matching_symbols_psymtab (const char *name, domain_enum namespace, } } +/* A helper for expand_symtabs_matching_via_partial that handles + searching included psymtabs. This returns 1 if a symbol is found, + and zero otherwise. It also updates the 'searched_flag' on the + various psymtabs that it searches. */ + +static int +recursively_search_psymtabs (struct partial_symtab *ps, + struct objfile *objfile, + enum search_domain kind, + int (*name_matcher) (const char *, void *), + void *data) +{ + struct partial_symbol **psym; + struct partial_symbol **bound, **gbound, **sbound; + int keep_going = 1; + int result = PST_SEARCHED_AND_NOT_FOUND; + int i; + + if (ps->searched_flag != PST_NOT_SEARCHED) + return ps->searched_flag == PST_SEARCHED_AND_FOUND; + + /* Recurse into shared psymtabs first, because they may have already + been searched, and this could save some time. */ + for (i = 0; i < ps->number_of_dependencies; ++i) + { + int r; + + /* Skip non-shared dependencies, these are handled elsewhere. */ + if (ps->dependencies[i]->user == NULL) + continue; + + r = recursively_search_psymtabs (ps->dependencies[i], + objfile, kind, name_matcher, data); + if (r != 0) + { + ps->searched_flag = PST_SEARCHED_AND_FOUND; + return 1; + } + } + + gbound = (objfile->global_psymbols.list + + ps->globals_offset + ps->n_global_syms); + sbound = (objfile->static_psymbols.list + + ps->statics_offset + ps->n_static_syms); + bound = gbound; + + /* Go through all of the symbols stored in a partial + symtab in one loop. */ + psym = objfile->global_psymbols.list + ps->globals_offset; + while (keep_going) + { + if (psym >= bound) + { + if (bound == gbound && ps->n_static_syms != 0) + { + psym = objfile->static_psymbols.list + ps->statics_offset; + bound = sbound; + } + else + keep_going = 0; + continue; + } + else + { + QUIT; + + if ((kind == ALL_DOMAIN + || (kind == VARIABLES_DOMAIN + && SYMBOL_CLASS (*psym) != LOC_TYPEDEF + && SYMBOL_CLASS (*psym) != LOC_BLOCK) + || (kind == FUNCTIONS_DOMAIN + && SYMBOL_CLASS (*psym) == LOC_BLOCK) + || (kind == TYPES_DOMAIN + && SYMBOL_CLASS (*psym) == LOC_TYPEDEF)) + && (*name_matcher) (SYMBOL_SEARCH_NAME (*psym), data)) + { + /* Found a match, so notify our caller. */ + result = PST_SEARCHED_AND_FOUND; + keep_going = 0; + } + } + psym++; + } + + ps->searched_flag = result; + return result == PST_SEARCHED_AND_FOUND; +} + static void expand_symtabs_matching_via_partial (struct objfile *objfile, - int (*file_matcher) (const char *, void *), - int (*name_matcher) (const struct language_defn *, const char *, void *), + int (*file_matcher) (const char *, void *, int basenames), + int (*name_matcher) (const char *, void *), enum search_domain kind, void *data) { struct partial_symtab *ps; + /* Clear the search flags. */ ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, ps) { - struct partial_symbol **psym; - struct partial_symbol **bound, **gbound, **sbound; - int keep_going = 1; + ps->searched_flag = PST_NOT_SEARCHED; + } + ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, ps) + { if (ps->readin) continue; - if (file_matcher && ! (*file_matcher) (ps->filename, data)) + /* We skip shared psymtabs because file-matching doesn't apply + to them; but we search them later in the loop. */ + if (ps->user != NULL) continue; - gbound = objfile->global_psymbols.list - + ps->globals_offset + ps->n_global_syms; - sbound = objfile->static_psymbols.list - + ps->statics_offset + ps->n_static_syms; - bound = gbound; - - /* Go through all of the symbols stored in a partial - symtab in one loop. */ - psym = objfile->global_psymbols.list + ps->globals_offset; - while (keep_going) + if (file_matcher) { - if (psym >= bound) - { - if (bound == gbound && ps->n_static_syms != 0) - { - psym = objfile->static_psymbols.list + ps->statics_offset; - bound = sbound; - } - else - keep_going = 0; - continue; - } - else - { - QUIT; - - if ((kind == ALL_DOMAIN - || (kind == VARIABLES_DOMAIN - && SYMBOL_CLASS (*psym) != LOC_TYPEDEF - && SYMBOL_CLASS (*psym) != LOC_BLOCK) - || (kind == FUNCTIONS_DOMAIN - && SYMBOL_CLASS (*psym) == LOC_BLOCK) - || (kind == TYPES_DOMAIN - && SYMBOL_CLASS (*psym) == LOC_TYPEDEF)) - && (*name_matcher) (current_language, - SYMBOL_NATURAL_NAME (*psym), data)) - { - PSYMTAB_TO_SYMTAB (ps); - keep_going = 0; - } - } - psym++; + if (ps->anonymous) + continue; + + /* Before we invoke realpath, which can get expensive when many + files are involved, do a quick comparison of the basenames. */ + if (!(*file_matcher) (ps->filename, data, 0) + && (basenames_may_differ + || (*file_matcher) (lbasename (ps->filename), data, 1)) + && !(*file_matcher) (psymtab_to_fullname (ps), data, 0)) + continue; } + + if (recursively_search_psymtabs (ps, objfile, kind, name_matcher, data)) + psymtab_to_symtab (objfile, ps); } } @@ -1329,13 +1422,12 @@ const struct quick_symbol_functions psym_functions = forget_cached_source_info_partial, partial_map_symtabs_matching_filename, lookup_symbol_aux_psymtabs, - pre_expand_symtabs_matching_psymtabs, print_psymtab_stats_for_objfile, dump_psymtabs_for_objfile, relocate_psymtabs, read_symtabs_for_function, expand_partial_symbol_tables, - read_psymtabs_with_filename, + read_psymtabs_with_fullname, find_symbol_file_from_partial, map_matching_symbols_psymtab, expand_symtabs_matching_via_partial, @@ -1359,11 +1451,11 @@ compare_psymbols (const void *s1p, const void *s2p) } void -sort_pst_symbols (struct partial_symtab *pst) +sort_pst_symbols (struct objfile *objfile, struct partial_symtab *pst) { /* Sort the global list; don't sort the static list. */ - qsort (pst->objfile->global_psymbols.list + pst->globals_offset, + qsort (objfile->global_psymbols.list + pst->globals_offset, pst->n_global_syms, sizeof (struct partial_symbol *), compare_psymbols); } @@ -1569,18 +1661,7 @@ append_psymbol_to_list (struct psymbol_allocation_list *list, Since one arg is a struct, we pass in a ptr and deref it (sigh). Return the partial symbol that has been added. */ -/* NOTE: carlton/2003-09-11: The reason why we return the partial - symbol is so that callers can get access to the symbol's demangled - name, which they don't have any cheap way to determine otherwise. - (Currenly, dwarf2read.c is the only file who uses that information, - though it's possible that other readers might in the future.) - Elena wasn't thrilled about that, and I don't blame her, but we - couldn't come up with a better way to get that information. If - it's needed in other situations, we could consider breaking up - SYMBOL_SET_NAMES to provide access to the demangled name lookup - cache. */ - -const struct partial_symbol * +void add_psymbol_to_list (const char *name, int namelength, int copy_name, domain_enum domain, enum address_class class, @@ -1600,11 +1681,10 @@ add_psymbol_to_list (const char *name, int namelength, int copy_name, /* Do not duplicate global partial symbols. */ if (list == &objfile->global_psymbols && !added) - return psym; + return; /* Save pointer to partial symbol in psymtab, growing symtab if needed. */ append_psymbol_to_list (list, psym, objfile); - return psym; } /* Initialize storage for partial symbols. */ @@ -1625,7 +1705,7 @@ init_psymbol_list (struct objfile *objfile, int total_symbols) /* Current best guess is that approximately a twentieth of the total symbols (in a debugging file) are global or static - oriented symbols. */ + oriented symbols, then multiply that by slop factor of two. */ objfile->global_psymbols.size = total_symbols / 10; objfile->static_psymbols.size = total_symbols / 10; @@ -1662,23 +1742,42 @@ allocate_psymtab (const char *filename, struct objfile *objfile) sizeof (struct partial_symtab)); memset (psymtab, 0, sizeof (struct partial_symtab)); - psymtab->filename = obsavestring (filename, strlen (filename), - &objfile->objfile_obstack); + psymtab->filename = obstack_copy0 (&objfile->objfile_obstack, + filename, strlen (filename)); psymtab->symtab = NULL; /* Prepend it to the psymtab list for the objfile it belongs to. Psymtabs are searched in most recent inserted -> least recent inserted order. */ - psymtab->objfile = objfile; psymtab->next = objfile->psymtabs; objfile->psymtabs = psymtab; + if (symtab_create_debug) + { + /* Be a bit clever with debugging messages, and don't print objfile + every time, only when it changes. */ + static char *last_objfile_name = NULL; + + if (last_objfile_name == NULL + || strcmp (last_objfile_name, objfile->name) != 0) + { + xfree (last_objfile_name); + last_objfile_name = xstrdup (objfile->name); + fprintf_unfiltered (gdb_stdlog, + "Creating one or more psymtabs for objfile %s ...\n", + last_objfile_name); + } + fprintf_unfiltered (gdb_stdlog, + "Created psymtab %s for module %s.\n", + host_address_to_string (psymtab), filename); + } + return (psymtab); } void -discard_psymtab (struct partial_symtab *pst) +discard_psymtab (struct objfile *objfile, struct partial_symtab *pst) { struct partial_symtab **prev_pst; @@ -1691,20 +1790,58 @@ discard_psymtab (struct partial_symtab *pst) /* First, snip it out of the psymtab chain. */ - prev_pst = &(pst->objfile->psymtabs); + prev_pst = &(objfile->psymtabs); while ((*prev_pst) != pst) prev_pst = &((*prev_pst)->next); (*prev_pst) = pst->next; /* Next, put it on a free list for recycling. */ - pst->next = pst->objfile->free_psymtabs; - pst->objfile->free_psymtabs = pst; + pst->next = objfile->free_psymtabs; + objfile->free_psymtabs = pst; +} + +/* An object of this type is passed to discard_psymtabs_upto. */ + +struct psymtab_state +{ + /* The objfile where psymtabs are discarded. */ + + struct objfile *objfile; + + /* The first psymtab to save. */ + + struct partial_symtab *save; +}; + +/* A cleanup function used by make_cleanup_discard_psymtabs. */ + +static void +discard_psymtabs_upto (void *arg) +{ + struct psymtab_state *state = arg; + + while (state->objfile->psymtabs != state->save) + discard_psymtab (state->objfile, state->objfile->psymtabs); +} + +/* Return a new cleanup that discards all psymtabs created in OBJFILE + after this function is called. */ + +struct cleanup * +make_cleanup_discard_psymtabs (struct objfile *objfile) +{ + struct psymtab_state *state = XNEW (struct psymtab_state); + + state->objfile = objfile; + state->save = objfile->psymtabs; + + return make_cleanup_dtor (discard_psymtabs_upto, state, xfree); } -void +static void maintenance_print_psymbols (char *args, int from_tty) { char **argv; @@ -1743,16 +1880,17 @@ print-psymbols takes an output file name and optional symbol file name")); perror_with_name (filename); make_cleanup_ui_file_delete (outfile); - immediate_quit++; ALL_PSYMTABS (objfile, ps) - if (symname == NULL || filename_cmp (symname, ps->filename) == 0) - dump_psymtab (objfile, ps, outfile); - immediate_quit--; + { + QUIT; + if (symname == NULL || filename_cmp (symname, ps->filename) == 0) + dump_psymtab (objfile, ps, outfile); + } do_cleanups (cleanups); } /* List all the partial symbol tables whose names match REGEXP (optional). */ -void +static void maintenance_info_psymtabs (char *regexp, int from_tty) { struct program_space *pspace; @@ -1811,7 +1949,7 @@ maintenance_info_psymtabs (char *regexp, int from_tty) if (psymtab->n_global_syms) { printf_filtered ("(* (struct partial_symbol **) %s @ %d)\n", - host_address_to_string (psymtab->objfile->global_psymbols.list + host_address_to_string (objfile->global_psymbols.list + psymtab->globals_offset), psymtab->n_global_syms); } @@ -1821,7 +1959,7 @@ maintenance_info_psymtabs (char *regexp, int from_tty) if (psymtab->n_static_syms) { printf_filtered ("(* (struct partial_symbol **) %s @ %d)\n", - host_address_to_string (psymtab->objfile->static_psymbols.list + host_address_to_string (objfile->static_psymbols.list + psymtab->statics_offset), psymtab->n_static_syms); } @@ -1858,7 +1996,7 @@ maintenance_info_psymtabs (char *regexp, int from_tty) /* Check consistency of psymtabs and symtabs. */ -void +static void maintenance_check_symtabs (char *ignore, int from_tty) { struct symbol *sym; @@ -1874,12 +2012,12 @@ maintenance_check_symtabs (char *ignore, int from_tty) { struct gdbarch *gdbarch = get_objfile_arch (objfile); - s = PSYMTAB_TO_SYMTAB (ps); + s = psymtab_to_symtab (objfile, ps); if (s == NULL) continue; bv = BLOCKVECTOR (s); b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - psym = ps->objfile->static_psymbols.list + ps->statics_offset; + psym = objfile->static_psymbols.list + ps->statics_offset; length = ps->n_static_syms; while (length--) { @@ -1896,7 +2034,7 @@ maintenance_check_symtabs (char *ignore, int from_tty) psym++; } b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - psym = ps->objfile->global_psymbols.list + ps->globals_offset; + psym = objfile->global_psymbols.list + ps->globals_offset; length = ps->n_global_syms; while (length--) { @@ -1945,8 +2083,7 @@ maintenance_check_symtabs (char *ignore, int from_tty) void -expand_partial_symbol_names (int (*fun) (const struct language_defn *, - const char *, void *), +expand_partial_symbol_names (int (*fun) (const char *, void *), void *data) { struct objfile *objfile; @@ -1972,3 +2109,25 @@ map_partial_symbol_filenames (symbol_filename_ftype *fun, void *data, need_fullname); } } + +extern initialize_file_ftype _initialize_psymtab; + +void +_initialize_psymtab (void) +{ + add_cmd ("psymbols", class_maintenance, maintenance_print_psymbols, _("\ +Print dump of current partial symbol definitions.\n\ +Entries in the partial symbol table are dumped to file OUTFILE.\n\ +If a SOURCE file is specified, dump only that file's partial symbols."), + &maintenanceprintlist); + + add_cmd ("psymtabs", class_maintenance, maintenance_info_psymtabs, _("\ +List the partial symbol tables for all object files.\n\ +This does not include information about individual partial symbols,\n\ +just the symbol table structures themselves."), + &maintenanceinfolist); + + add_cmd ("check-symtabs", class_maintenance, maintenance_check_symtabs, + _("Check consistency of psymtabs and symtabs."), + &maintenancelist); +} diff --git a/contrib/gdb-7/gdb/psymtab.h b/contrib/gdb-7/gdb/psymtab.h index 8fd91ee283..f32191a40c 100644 --- a/contrib/gdb-7/gdb/psymtab.h +++ b/contrib/gdb-7/gdb/psymtab.h @@ -1,6 +1,6 @@ /* Public partial symbol table definitions. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -30,8 +30,7 @@ extern struct psymbol_bcache *psymbol_bcache_init (void); extern void psymbol_bcache_free (struct psymbol_bcache *); extern struct bcache *psymbol_bcache_get_bcache (struct psymbol_bcache *); -void expand_partial_symbol_names (int (*fun) (const struct language_defn *, - const char *, void *), +void expand_partial_symbol_names (int (*fun) (const char *, void *), void *data); void map_partial_symbol_filenames (symbol_filename_ftype *fun, void *data, diff --git a/contrib/gdb-7/gdb/python/lib/gdb/__init__.py b/contrib/gdb-7/gdb/python/lib/gdb/__init__.py index a82e4959e4..6311583092 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/__init__.py +++ b/contrib/gdb-7/gdb/python/lib/gdb/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2012 Free Software Foundation, Inc. +# Copyright (C) 2010-2013 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 @@ -14,28 +14,111 @@ # along with this program. If not, see . import traceback +import os +import sys +import _gdb + +if sys.version_info[0] > 2: + # Python 3 moved "reload" + from imp import reload + +from _gdb import * + +class _GdbFile (object): + # These two are needed in Python 3 + encoding = "UTF-8" + errors = "strict" + + def close(self): + # Do nothing. + return None + + def isatty(self): + return False + + def writelines(self, iterable): + for line in iterable: + self.write(line) + + def flush(self): + flush() + +class GdbOutputFile (_GdbFile): + def write(self, s): + write(s, stream=STDOUT) + +sys.stdout = GdbOutputFile() + +class GdbOutputErrorFile (_GdbFile): + def write(self, s): + write(s, stream=STDERR) + +sys.stderr = GdbOutputErrorFile() + +# Default prompt hook does nothing. +prompt_hook = None + +# Ensure that sys.argv is set to something. +# We do not use PySys_SetArgvEx because it did not appear until 2.6.6. +sys.argv = [''] + +# Initial pretty printers. +pretty_printers = [] + +# Initial type printers. +type_printers = [] + +# Convenience variable to GDB's python directory +PYTHONDIR = os.path.dirname(os.path.dirname(__file__)) # Auto-load all functions/commands. -# Modules to auto-load, and the paths where those modules exist. +# Packages to auto-load. -module_dict = { - 'gdb.function': os.path.join(gdb.PYTHONDIR, 'gdb', 'function'), - 'gdb.command': os.path.join(gdb.PYTHONDIR, 'gdb', 'command') -} +packages = [ + 'function', + 'command' +] -# Iterate the dictionary, collating the Python files in each module +# pkgutil.iter_modules is not available prior to Python 2.6. Instead, +# manually iterate the list, collating the Python files in each module # path. Construct the module name, and import. -for module, location in module_dict.iteritems(): - if os.path.exists(location): - py_files = filter(lambda x: x.endswith('.py') and x != '__init__.py', - os.listdir(location)) - - for py_file in py_files: - # Construct from foo.py, gdb.module.foo - py_file = module + '.' + py_file[:-3] - try: - exec('import ' + py_file) - except: - print >> sys.stderr, traceback.format_exc() +def auto_load_packages(): + for package in packages: + location = os.path.join(os.path.dirname(__file__), package) + if os.path.exists(location): + py_files = filter(lambda x: x.endswith('.py') + and x != '__init__.py', + os.listdir(location)) + + for py_file in py_files: + # Construct from foo.py, gdb.module.foo + modname = "%s.%s.%s" % ( __name__, package, py_file[:-3] ) + try: + if modname in sys.modules: + # reload modules with duplicate names + reload(__import__(modname)) + else: + __import__(modname) + except: + sys.stderr.write (traceback.format_exc() + "\n") + +auto_load_packages() + +def GdbSetPythonDirectory(dir): + """Update sys.path, reload gdb and auto-load packages.""" + global PYTHONDIR + + try: + sys.path.remove(PYTHONDIR) + except ValueError: + pass + sys.path.insert(0, dir) + + PYTHONDIR = dir + + # note that reload overwrites the gdb module without deleting existing + # attributes + reload(__import__(__name__)) + auto_load_packages() diff --git a/contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py b/contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py index 0eb19f24a9..21eaef8d9c 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py +++ b/contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2012 Free Software Foundation, Inc. +# Copyright (C) 2010-2013 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 diff --git a/contrib/gdb-7/gdb/python/lib/gdb/command/explore.py b/contrib/gdb-7/gdb/python/lib/gdb/command/explore.py new file mode 100644 index 0000000000..dd77875dc1 --- /dev/null +++ b/contrib/gdb-7/gdb/python/lib/gdb/command/explore.py @@ -0,0 +1,760 @@ +# GDB 'explore' command. +# Copyright (C) 2012-2013 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 . + +"""Implementation of the GDB 'explore' command using the GDB Python API.""" + +import gdb +import sys + +if sys.version_info[0] > 2: + # Python 3 renamed raw_input to input + raw_input = input + +class Explorer(object): + """Internal class which invokes other explorers.""" + + # This map is filled by the Explorer.init_env() function + type_code_to_explorer_map = { } + + _SCALAR_TYPE_LIST = ( + gdb.TYPE_CODE_CHAR, + gdb.TYPE_CODE_INT, + gdb.TYPE_CODE_BOOL, + gdb.TYPE_CODE_FLT, + gdb.TYPE_CODE_VOID, + gdb.TYPE_CODE_ENUM, + ) + + @staticmethod + def guard_expr(expr): + length = len(expr) + guard = False + + if expr[0] == '(' and expr[length-1] == ')': + pass + else: + i = 0 + while i < length: + c = expr[i] + if (c == '_' or ('a' <= c and c <= 'z') or + ('A' <= c and c <= 'Z') or ('0' <= c and c <= '9')): + pass + else: + guard = True + break + i += 1 + + if guard: + return "(" + expr + ")" + else: + return expr + + @staticmethod + def explore_expr(expr, value, is_child): + """Main function to explore an expression value. + + Arguments: + expr: The expression string that is being explored. + value: The gdb.Value value of the expression. + is_child: Boolean value to indicate if the expression is a child. + An expression is a child if it is derived from the main + expression entered by the user. For example, if the user + entered an expression which evaluates to a struct, then + when exploring the fields of the struct, is_child is set + to True internally. + + Returns: + No return value. + """ + type_code = value.type.code + if type_code in Explorer.type_code_to_explorer_map: + explorer_class = Explorer.type_code_to_explorer_map[type_code] + while explorer_class.explore_expr(expr, value, is_child): + pass + else: + print ("Explorer for type '%s' not yet available.\n" % + str(value.type)) + + @staticmethod + def explore_type(name, datatype, is_child): + """Main function to explore a data type. + + Arguments: + name: The string representing the path to the data type being + explored. + datatype: The gdb.Type value of the data type being explored. + is_child: Boolean value to indicate if the name is a child. + A name is a child if it is derived from the main name + entered by the user. For example, if the user entered + the name of struct type, then when exploring the fields + of the struct, is_child is set to True internally. + + Returns: + No return value. + """ + type_code = datatype.code + if type_code in Explorer.type_code_to_explorer_map: + explorer_class = Explorer.type_code_to_explorer_map[type_code] + while explorer_class.explore_type(name, datatype, is_child): + pass + else: + print ("Explorer for type '%s' not yet available.\n" % + str(datatype)) + + @staticmethod + def init_env(): + """Initializes the Explorer environment. + This function should be invoked before starting any exploration. If + invoked before an exploration, it need not be invoked for subsequent + explorations. + """ + Explorer.type_code_to_explorer_map = { + gdb.TYPE_CODE_CHAR : ScalarExplorer, + gdb.TYPE_CODE_INT : ScalarExplorer, + gdb.TYPE_CODE_BOOL : ScalarExplorer, + gdb.TYPE_CODE_FLT : ScalarExplorer, + gdb.TYPE_CODE_VOID : ScalarExplorer, + gdb.TYPE_CODE_ENUM : ScalarExplorer, + gdb.TYPE_CODE_STRUCT : CompoundExplorer, + gdb.TYPE_CODE_UNION : CompoundExplorer, + gdb.TYPE_CODE_PTR : PointerExplorer, + gdb.TYPE_CODE_REF : ReferenceExplorer, + gdb.TYPE_CODE_TYPEDEF : TypedefExplorer, + gdb.TYPE_CODE_ARRAY : ArrayExplorer + } + + @staticmethod + def is_scalar_type(type): + """Checks whether a type is a scalar type. + A type is a scalar type of its type is + gdb.TYPE_CODE_CHAR or + gdb.TYPE_CODE_INT or + gdb.TYPE_CODE_BOOL or + gdb.TYPE_CODE_FLT or + gdb.TYPE_CODE_VOID or + gdb.TYPE_CODE_ENUM. + + Arguments: + type: The type to be checked. + + Returns: + 'True' if 'type' is a scalar type. 'False' otherwise. + """ + return type.code in Explorer._SCALAR_TYPE_LIST + + @staticmethod + def return_to_parent_value(): + """A utility function which prints that the current exploration session + is returning to the parent value. Useful when exploring values. + """ + print ("\nReturning to parent value...\n") + + @staticmethod + def return_to_parent_value_prompt(): + """A utility function which prompts the user to press the 'enter' key + so that the exploration session can shift back to the parent value. + Useful when exploring values. + """ + raw_input("\nPress enter to return to parent value: ") + + @staticmethod + def return_to_enclosing_type(): + """A utility function which prints that the current exploration session + is returning to the enclosing type. Useful when exploring types. + """ + print ("\nReturning to enclosing type...\n") + + @staticmethod + def return_to_enclosing_type_prompt(): + """A utility function which prompts the user to press the 'enter' key + so that the exploration session can shift back to the enclosing type. + Useful when exploring types. + """ + raw_input("\nPress enter to return to enclosing type: ") + + +class ScalarExplorer(object): + """Internal class used to explore scalar values.""" + + @staticmethod + def explore_expr(expr, value, is_child): + """Function to explore scalar values. + See Explorer.explore_expr and Explorer.is_scalar_type for more + information. + """ + print ("'%s' is a scalar value of type '%s'." % + (expr, value.type)) + print ("%s = %s" % (expr, str(value))) + + if is_child: + Explorer.return_to_parent_value_prompt() + Explorer.return_to_parent_value() + + return False + + @staticmethod + def explore_type(name, datatype, is_child): + """Function to explore scalar types. + See Explorer.explore_type and Explorer.is_scalar_type for more + information. + """ + if datatype.code == gdb.TYPE_CODE_ENUM: + if is_child: + print ("%s is of an enumerated type '%s'." % + (name, str(datatype))) + else: + print ("'%s' is an enumerated type." % name) + else: + if is_child: + print ("%s is of a scalar type '%s'." % + (name, str(datatype))) + else: + print ("'%s' is a scalar type." % name) + + if is_child: + Explorer.return_to_enclosing_type_prompt() + Explorer.return_to_enclosing_type() + + return False + + +class PointerExplorer(object): + """Internal class used to explore pointer values.""" + + @staticmethod + def explore_expr(expr, value, is_child): + """Function to explore pointer values. + See Explorer.explore_expr for more information. + """ + print ("'%s' is a pointer to a value of type '%s'" % + (expr, str(value.type.target()))) + option = raw_input("Continue exploring it as a pointer to a single " + "value [y/n]: ") + if option == "y": + deref_value = None + try: + deref_value = value.dereference() + str(deref_value) + except gdb.MemoryError: + print ("'%s' a pointer pointing to an invalid memory " + "location." % expr) + if is_child: + Explorer.return_to_parent_value_prompt() + return False + Explorer.explore_expr("*%s" % Explorer.guard_expr(expr), + deref_value, is_child) + return False + + option = raw_input("Continue exploring it as a pointer to an " + "array [y/n]: ") + if option == "y": + while True: + index = 0 + try: + index = int(raw_input("Enter the index of the element you " + "want to explore in '%s': " % expr)) + except ValueError: + break + element_expr = "%s[%d]" % (Explorer.guard_expr(expr), index) + element = value[index] + try: + str(element) + except gdb.MemoryError: + print ("Cannot read value at index %d." % index) + continue + Explorer.explore_expr(element_expr, element, True) + return False + + if is_child: + Explorer.return_to_parent_value() + return False + + @staticmethod + def explore_type(name, datatype, is_child): + """Function to explore pointer types. + See Explorer.explore_type for more information. + """ + target_type = datatype.target() + print ("\n%s is a pointer to a value of type '%s'." % + (name, str(target_type))) + + Explorer.explore_type("the pointee type of %s" % name, + target_type, + is_child) + return False + + +class ReferenceExplorer(object): + """Internal class used to explore reference (TYPE_CODE_REF) values.""" + + @staticmethod + def explore_expr(expr, value, is_child): + """Function to explore array values. + See Explorer.explore_expr for more information. + """ + referenced_value = value.referenced_value() + Explorer.explore_expr(expr, referenced_value, is_child) + return False + + @staticmethod + def explore_type(name, datatype, is_child): + """Function to explore pointer types. + See Explorer.explore_type for more information. + """ + target_type = datatype.target() + Explorer.explore_type(name, target_type, is_child) + return False + + +class ArrayExplorer(object): + """Internal class used to explore arrays.""" + + @staticmethod + def explore_expr(expr, value, is_child): + """Function to explore array values. + See Explorer.explore_expr for more information. + """ + target_type = value.type.target() + print ("'%s' is an array of '%s'." % (expr, str(target_type))) + index = 0 + try: + index = int(raw_input("Enter the index of the element you want to " + "explore in '%s': " % expr)) + except ValueError: + if is_child: + Explorer.return_to_parent_value() + return False + + element = None + try: + element = value[index] + str(element) + except gdb.MemoryError: + print ("Cannot read value at index %d." % index) + raw_input("Press enter to continue... ") + return True + + Explorer.explore_expr("%s[%d]" % (Explorer.guard_expr(expr), index), + element, True) + return True + + @staticmethod + def explore_type(name, datatype, is_child): + """Function to explore array types. + See Explorer.explore_type for more information. + """ + target_type = datatype.target() + print ("%s is an array of '%s'." % (name, str(target_type))) + + Explorer.explore_type("the array element of %s" % name, target_type, + is_child) + return False + + +class CompoundExplorer(object): + """Internal class used to explore struct, classes and unions.""" + + @staticmethod + def _print_fields(print_list): + """Internal function which prints the fields of a struct/class/union. + """ + max_field_name_length = 0 + for pair in print_list: + if max_field_name_length < len(pair[0]): + max_field_name_length = len(pair[0]) + + for pair in print_list: + print (" %*s = %s" % (max_field_name_length, pair[0], pair[1])) + + @staticmethod + def _get_real_field_count(fields): + real_field_count = 0; + for field in fields: + if not field.artificial: + real_field_count = real_field_count + 1 + + return real_field_count + + @staticmethod + def explore_expr(expr, value, is_child): + """Function to explore structs/classes and union values. + See Explorer.explore_expr for more information. + """ + datatype = value.type + type_code = datatype.code + fields = datatype.fields() + + if type_code == gdb.TYPE_CODE_STRUCT: + type_desc = "struct/class" + else: + type_desc = "union" + + if CompoundExplorer._get_real_field_count(fields) == 0: + print ("The value of '%s' is a %s of type '%s' with no fields." % + (expr, type_desc, str(value.type))) + if is_child: + Explorer.return_to_parent_value_prompt() + return False + + print ("The value of '%s' is a %s of type '%s' with the following " + "fields:\n" % (expr, type_desc, str(value.type))) + + has_explorable_fields = False + choice_to_compound_field_map = { } + current_choice = 0 + print_list = [ ] + for field in fields: + if field.artificial: + continue + field_full_name = Explorer.guard_expr(expr) + "." + field.name + if field.is_base_class: + field_value = value.cast(field.type) + else: + field_value = value[field.name] + literal_value = "" + if type_code == gdb.TYPE_CODE_UNION: + literal_value = ("" % (current_choice, str(field.type))) + has_explorable_fields = True + else: + if Explorer.is_scalar_type(field.type): + literal_value = ("%s .. (Value of type '%s')" % + (str(field_value), str(field.type))) + else: + if field.is_base_class: + field_desc = "base class" + else: + field_desc = "field" + literal_value = ("" % + (current_choice, field_desc, + str(field.type))) + has_explorable_fields = True + + choice_to_compound_field_map[str(current_choice)] = ( + field_full_name, field_value) + current_choice = current_choice + 1 + + print_list.append((field.name, literal_value)) + + CompoundExplorer._print_fields(print_list) + print ("") + + if has_explorable_fields: + choice = raw_input("Enter the field number of choice: ") + if choice in choice_to_compound_field_map: + Explorer.explore_expr(choice_to_compound_field_map[choice][0], + choice_to_compound_field_map[choice][1], + True) + return True + else: + if is_child: + Explorer.return_to_parent_value() + else: + if is_child: + Explorer.return_to_parent_value_prompt() + + return False + + @staticmethod + def explore_type(name, datatype, is_child): + """Function to explore struct/class and union types. + See Explorer.explore_type for more information. + """ + type_code = datatype.code + type_desc = "" + if type_code == gdb.TYPE_CODE_STRUCT: + type_desc = "struct/class" + else: + type_desc = "union" + + fields = datatype.fields() + if CompoundExplorer._get_real_field_count(fields) == 0: + if is_child: + print ("%s is a %s of type '%s' with no fields." % + (name, type_desc, str(datatype))) + Explorer.return_to_enclosing_type_prompt() + else: + print ("'%s' is a %s with no fields." % (name, type_desc)) + return False + + if is_child: + print ("%s is a %s of type '%s' " + "with the following fields:\n" % + (name, type_desc, str(datatype))) + else: + print ("'%s' is a %s with the following " + "fields:\n" % + (name, type_desc)) + + has_explorable_fields = False + current_choice = 0 + choice_to_compound_field_map = { } + print_list = [ ] + for field in fields: + if field.artificial: + continue + if field.is_base_class: + field_desc = "base class" + else: + field_desc = "field" + rhs = ("" % + (current_choice, field_desc, str(field.type))) + print_list.append((field.name, rhs)) + choice_to_compound_field_map[str(current_choice)] = ( + field.name, field.type, field_desc) + current_choice = current_choice + 1 + + CompoundExplorer._print_fields(print_list) + print ("") + + if len(choice_to_compound_field_map) > 0: + choice = raw_input("Enter the field number of choice: ") + if choice in choice_to_compound_field_map: + if is_child: + new_name = ("%s '%s' of %s" % + (choice_to_compound_field_map[choice][2], + choice_to_compound_field_map[choice][0], + name)) + else: + new_name = ("%s '%s' of '%s'" % + (choice_to_compound_field_map[choice][2], + choice_to_compound_field_map[choice][0], + name)) + Explorer.explore_type(new_name, + choice_to_compound_field_map[choice][1], True) + return True + else: + if is_child: + Explorer.return_to_enclosing_type() + else: + if is_child: + Explorer.return_to_enclosing_type_prompt() + + return False + + +class TypedefExplorer(object): + """Internal class used to explore values whose type is a typedef.""" + + @staticmethod + def explore_expr(expr, value, is_child): + """Function to explore typedef values. + See Explorer.explore_expr for more information. + """ + actual_type = value.type.strip_typedefs() + print ("The value of '%s' is of type '%s' " + "which is a typedef of type '%s'" % + (expr, str(value.type), str(actual_type))) + + Explorer.explore_expr(expr, value.cast(actual_type), is_child) + return False + + @staticmethod + def explore_type(name, datatype, is_child): + """Function to explore typedef types. + See Explorer.explore_type for more information. + """ + actual_type = datatype.strip_typedefs() + if is_child: + print ("The type of %s is a typedef of type '%s'." % + (name, str(actual_type))) + else: + print ("The type '%s' is a typedef of type '%s'." % + (name, str(actual_type))) + + Explorer.explore_type(name, actual_type, is_child) + return False + + +class ExploreUtils(object): + """Internal class which provides utilities for the main command classes.""" + + @staticmethod + def check_args(name, arg_str): + """Utility to check if adequate number of arguments are passed to an + explore command. + + Arguments: + name: The name of the explore command. + arg_str: The argument string passed to the explore command. + + Returns: + True if adequate arguments are passed, false otherwise. + + Raises: + gdb.GdbError if adequate arguments are not passed. + """ + if len(arg_str) < 1: + raise gdb.GdbError("ERROR: '%s' requires an argument." + % name) + return False + else: + return True + + @staticmethod + def get_type_from_str(type_str): + """A utility function to deduce the gdb.Type value from a string + representing the type. + + Arguments: + type_str: The type string from which the gdb.Type value should be + deduced. + + Returns: + The deduced gdb.Type value if possible, None otherwise. + """ + try: + # Assume the current language to be C/C++ and make a try. + return gdb.parse_and_eval("(%s *)0" % type_str).type.target() + except RuntimeError: + # If assumption of current language to be C/C++ was wrong, then + # lookup the type using the API. + try: + return gdb.lookup_type(type_str) + except RuntimeError: + return None + + @staticmethod + def get_value_from_str(value_str): + """A utility function to deduce the gdb.Value value from a string + representing the value. + + Arguments: + value_str: The value string from which the gdb.Value value should + be deduced. + + Returns: + The deduced gdb.Value value if possible, None otherwise. + """ + try: + return gdb.parse_and_eval(value_str) + except RuntimeError: + return None + + +class ExploreCommand(gdb.Command): + """Explore a value or a type valid in the current context. + + Usage: + + explore ARG + + - ARG is either a valid expression or a type name. + - At any stage of exploration, hit the return key (instead of a + choice, if any) to return to the enclosing type or value. + """ + + def __init__(self): + super(ExploreCommand, self).__init__(name = "explore", + command_class = gdb.COMMAND_DATA, + prefix = True) + + def invoke(self, arg_str, from_tty): + if ExploreUtils.check_args("explore", arg_str) == False: + return + + # Check if it is a value + value = ExploreUtils.get_value_from_str(arg_str) + if value is not None: + Explorer.explore_expr(arg_str, value, False) + return + + # If it is not a value, check if it is a type + datatype = ExploreUtils.get_type_from_str(arg_str) + if datatype is not None: + Explorer.explore_type(arg_str, datatype, False) + return + + # If it is neither a value nor a type, raise an error. + raise gdb.GdbError( + ("'%s' neither evaluates to a value nor is a type " + "in the current context." % + arg_str)) + + +class ExploreValueCommand(gdb.Command): + """Explore value of an expression valid in the current context. + + Usage: + + explore value ARG + + - ARG is a valid expression. + - At any stage of exploration, hit the return key (instead of a + choice, if any) to return to the enclosing value. + """ + + def __init__(self): + super(ExploreValueCommand, self).__init__( + name = "explore value", command_class = gdb.COMMAND_DATA) + + def invoke(self, arg_str, from_tty): + if ExploreUtils.check_args("explore value", arg_str) == False: + return + + value = ExploreUtils.get_value_from_str(arg_str) + if value is None: + raise gdb.GdbError( + (" '%s' does not evaluate to a value in the current " + "context." % + arg_str)) + return + + Explorer.explore_expr(arg_str, value, False) + + +class ExploreTypeCommand(gdb.Command): + """Explore a type or the type of an expression valid in the current + context. + + Usage: + + explore type ARG + + - ARG is a valid expression or a type name. + - At any stage of exploration, hit the return key (instead of a + choice, if any) to return to the enclosing type. + """ + + def __init__(self): + super(ExploreTypeCommand, self).__init__( + name = "explore type", command_class = gdb.COMMAND_DATA) + + def invoke(self, arg_str, from_tty): + if ExploreUtils.check_args("explore type", arg_str) == False: + return + + datatype = ExploreUtils.get_type_from_str(arg_str) + if datatype is not None: + Explorer.explore_type(arg_str, datatype, False) + return + + value = ExploreUtils.get_value_from_str(arg_str) + if value is not None: + print ("'%s' is of type '%s'." % (arg_str, str(value.type))) + Explorer.explore_type(str(value.type), value.type, False) + return + + raise gdb.GdbError(("'%s' is not a type or value in the current " + "context." % arg_str)) + + +Explorer.init_env() + +ExploreCommand() +ExploreValueCommand() +ExploreTypeCommand() diff --git a/contrib/gdb-7/gdb/python/lib/gdb/command/pretty_printers.py b/contrib/gdb-7/gdb/python/lib/gdb/command/pretty_printers.py index 3ae3517edd..7b03e3a9d6 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/command/pretty_printers.py +++ b/contrib/gdb-7/gdb/python/lib/gdb/command/pretty_printers.py @@ -1,5 +1,5 @@ # Pretty-printer commands. -# Copyright (C) 2010-2012 Free Software Foundation, Inc. +# Copyright (C) 2010-2013 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 @@ -124,21 +124,17 @@ class InfoPrettyPrinter(gdb.Command): """Print a list of pretty-printers.""" # A potential enhancement is to provide an option to list printers in # "lookup order" (i.e. unsorted). - sorted_pretty_printers = copy.copy(pretty_printers) - sorted_pretty_printers.sort(lambda x, y: - cmp(self.printer_name(x), - self.printer_name(y))) + sorted_pretty_printers = sorted (copy.copy(pretty_printers), + key = self.printer_name) for printer in sorted_pretty_printers: name = self.printer_name(printer) enabled = self.enabled_string(printer) if name_re.match(name): - print " %s%s" % (name, enabled) + print (" %s%s" % (name, enabled)) if (hasattr(printer, "subprinters") and printer.subprinters is not None): - sorted_subprinters = copy.copy(printer.subprinters) - sorted_subprinters.sort(lambda x, y: - cmp(self.printer_name(x), - self.printer_name(y))) + sorted_subprinters = sorted (copy.copy(printer.subprinters), + key = self.printer_name) for subprinter in sorted_subprinters: if (not subname_re or subname_re.match(subprinter.name)): @@ -150,7 +146,7 @@ class InfoPrettyPrinter(gdb.Command): obj_name_to_match, object_re, name_re, subname_re): """Subroutine of invoke to simplify it.""" if printer_list and object_re.match(obj_name_to_match): - print title + print (title) self.list_pretty_printers(printer_list, name_re, subname_re) def invoke(self, arg, from_tty): @@ -219,7 +215,7 @@ def show_pretty_printer_enabled_summary(): We count subprinters individually. """ (enabled_count, total_count) = count_all_enabled_printers() - print "%d of %d printers enabled" % (enabled_count, total_count) + print ("%d of %d printers enabled" % (enabled_count, total_count)) def do_enable_pretty_printer_1 (pretty_printers, name_re, subname_re, flag): @@ -301,7 +297,7 @@ def do_enable_pretty_printer (arg, flag): state = "enabled" else: state = "disabled" - print "%d %s %s" % (total, pluralize("printer", total), state) + print ("%d %s %s" % (total, pluralize("printer", total), state)) # Print the total list of printers currently enabled/disabled. # This is to further assist the user in determining whether the result diff --git a/contrib/gdb-7/gdb/python/lib/gdb/command/prompt.py b/contrib/gdb-7/gdb/python/lib/gdb/command/prompt.py index 2bc03ef3e1..394e40c504 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/command/prompt.py +++ b/contrib/gdb-7/gdb/python/lib/gdb/command/prompt.py @@ -1,5 +1,5 @@ # Extended prompt. -# Copyright (C) 2011-2012 Free Software Foundation, Inc. +# Copyright (C) 2011-2013 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 diff --git a/contrib/gdb-7/gdb/python/lib/gdb/command/type_printers.py b/contrib/gdb-7/gdb/python/lib/gdb/command/type_printers.py new file mode 100644 index 0000000000..81f2ea1622 --- /dev/null +++ b/contrib/gdb-7/gdb/python/lib/gdb/command/type_printers.py @@ -0,0 +1,125 @@ +# Type printer commands. +# Copyright (C) 2010-2013 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 copy +import gdb + +"""GDB commands for working with type-printers.""" + +class InfoTypePrinter(gdb.Command): + """GDB command to list all registered type-printers. + + Usage: info type-printers + """ + + def __init__ (self): + super(InfoTypePrinter, self).__init__("info type-printers", + gdb.COMMAND_DATA) + + def list_type_printers(self, type_printers): + """Print a list of type printers.""" + # A potential enhancement is to provide an option to list printers in + # "lookup order" (i.e. unsorted). + sorted_type_printers = sorted (copy.copy(type_printers), + key = lambda x: x.name) + for printer in sorted_type_printers: + if printer.enabled: + enabled = '' + else: + enabled = " [disabled]" + print (" %s%s" % (printer.name, enabled)) + + def invoke(self, arg, from_tty): + """GDB calls this to perform the command.""" + sep = '' + for objfile in gdb.objfiles(): + if objfile.type_printers: + print ("%sType printers for %s:" % (sep, objfile.name)) + self.list_type_printers(objfile.type_printers) + sep = '\n' + if gdb.current_progspace().type_printers: + print ("%sType printers for program space:" % sep) + self.list_type_printers(gdb.current_progspace().type_printers) + sep = '\n' + if gdb.type_printers: + print ("%sGlobal type printers:" % sep) + self.list_type_printers(gdb.type_printers) + +class _EnableOrDisableCommand(gdb.Command): + def __init__(self, setting, name): + super(_EnableOrDisableCommand, self).__init__(name, gdb.COMMAND_DATA) + self.setting = setting + + def set_some(self, name, printers): + result = False + for p in printers: + if name == p.name: + p.enabled = self.setting + result = True + return result + + def invoke(self, arg, from_tty): + """GDB calls this to perform the command.""" + for name in arg.split(): + ok = False + for objfile in gdb.objfiles(): + if self.set_some(name, objfile.type_printers): + ok = True + if self.set_some(name, gdb.current_progspace().type_printers): + ok = True + if self.set_some(name, gdb.type_printers): + ok = True + if not ok: + print ("No type printer named '%s'" % name) + + def add_some(self, result, word, printers): + for p in printers: + if p.name.startswith(word): + result.append(p.name) + + def complete(self, text, word): + result = [] + for objfile in gdb.objfiles(): + self.add_some(result, word, objfile.type_printers) + self.add_some(result, word, gdb.current_progspace().type_printers) + self.add_some(result, word, gdb.type_printers) + return result + +class EnableTypePrinter(_EnableOrDisableCommand): + """GDB command to enable the specified type printer. + + Usage: enable type-printer NAME + + NAME is the name of the type-printer. + """ + + def __init__(self): + super(EnableTypePrinter, self).__init__(True, "enable type-printer") + +class DisableTypePrinter(_EnableOrDisableCommand): + """GDB command to disable the specified type-printer. + + Usage: disable type-printer NAME + + NAME is the name of the type-printer. + """ + + def __init__(self): + super(DisableTypePrinter, self).__init__(False, "disable type-printer") + +InfoTypePrinter() +EnableTypePrinter() +DisableTypePrinter() diff --git a/contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py b/contrib/gdb-7/gdb/python/lib/gdb/function/__init__.py similarity index 91% copy from contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py copy to contrib/gdb-7/gdb/python/lib/gdb/function/__init__.py index 0eb19f24a9..755bff9528 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/command/__init__.py +++ b/contrib/gdb-7/gdb/python/lib/gdb/function/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2010-2012 Free Software Foundation, Inc. +# Copyright (C) 2012-2013 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 @@ -12,5 +12,3 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - - diff --git a/contrib/gdb-7/gdb/python/lib/gdb/function/strfns.py b/contrib/gdb-7/gdb/python/lib/gdb/function/strfns.py new file mode 100644 index 0000000000..efdf9501da --- /dev/null +++ b/contrib/gdb-7/gdb/python/lib/gdb/function/strfns.py @@ -0,0 +1,108 @@ +# Useful gdb string convenience functions. +# Copyright (C) 2012-2013 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 . + +"""$_memeq, $_strlen, $_streq, $_regex""" + +import gdb +import re + + +class _MemEq(gdb.Function): + """$_memeq - compare bytes of memory + +Usage: + $_memeq(a, b, len) + +Returns: + True if len bytes at a and b compare equally. +""" + def __init__(self): + super(_MemEq, self).__init__("_memeq") + + def invoke(self, a, b, length): + if length < 0: + raise ValueError("length must be non-negative") + if length == 0: + return True + # The argument(s) to vector are [low_bound,]high_bound. + byte_vector = gdb.lookup_type("char").vector(length - 1) + ptr_byte_vector = byte_vector.pointer() + a_ptr = a.reinterpret_cast(ptr_byte_vector) + b_ptr = b.reinterpret_cast(ptr_byte_vector) + return a_ptr.dereference() == b_ptr.dereference() + + +class _StrLen(gdb.Function): + """$_strlen - compute string length + +Usage: + $_strlen(a) + +Returns: + Length of string a, assumed to be a string in the current language. +""" + def __init__(self): + super(_StrLen, self).__init__("_strlen") + + def invoke(self, a): + s = a.string() + return len(s) + + +class _StrEq(gdb.Function): + """$_streq - check string equality + +Usage: + $_streq(a, b) + +Returns: + True if a and b are identical strings in the current language. + +Example (amd64-linux): + catch syscall open + cond $bpnum $_streq((char*) $rdi, "foo") +""" + def __init__(self): + super(_StrEq, self).__init__("_streq") + + def invoke(self, a, b): + return a.string() == b.string() + + +class _RegEx(gdb.Function): + """$_regex - check if a string matches a regular expression + +Usage: + $_regex(string, regex) + +Returns: + True if string str (in the current language) matches the + regular expression regex. +""" + def __init__(self): + super(_RegEx, self).__init__("_regex") + + def invoke(self, string, regex): + s = string.string() + r = re.compile(regex.string()) + return bool(r.match(s)) + + +# GDB will import us automagically via gdb/__init__.py. +_MemEq() +_StrLen() +_StrEq() +_RegEx() diff --git a/contrib/gdb-7/gdb/python/lib/gdb/printing.py b/contrib/gdb-7/gdb/python/lib/gdb/printing.py index 98cfd27462..785a407c1b 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/printing.py +++ b/contrib/gdb-7/gdb/python/lib/gdb/printing.py @@ -1,5 +1,5 @@ # Pretty-printer utilities. -# Copyright (C) 2010-2012 Free Software Foundation, Inc. +# Copyright (C) 2010-2013 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 @@ -19,7 +19,12 @@ import gdb import gdb.types import re +import sys +if sys.version_info[0] > 2: + # Python 3 removed basestring and long + basestring = str + long = int class PrettyPrinter(object): """A basic pretty-printer. @@ -206,3 +211,53 @@ class RegexpCollectionPrettyPrinter(PrettyPrinter): # Cannot find a pretty printer. Return None. return None + +# A helper class for printing enum types. This class is instantiated +# with a list of enumerators to print a particular Value. +class _EnumInstance: + def __init__(self, enumerators, val): + self.enumerators = enumerators + self.val = val + + def to_string(self): + flag_list = [] + v = long(self.val) + any_found = False + for (e_name, e_value) in self.enumerators: + if v & e_value != 0: + flag_list.append(e_name) + v = v & ~e_value + any_found = True + if not any_found or v != 0: + # Leftover value. + flag_list.append('' % v) + return "0x%x [%s]" % (self.val, " | ".join(flag_list)) + +class FlagEnumerationPrinter(PrettyPrinter): + """A pretty-printer which can be used to print a flag-style enumeration. + A flag-style enumeration is one where the enumerators are or'd + together to create values. The new printer will print these + symbolically using '|' notation. The printer must be registered + manually. This printer is most useful when an enum is flag-like, + but has some overlap. GDB's built-in printing will not handle + this case, but this printer will attempt to.""" + + def __init__(self, enum_type): + super(FlagEnumerationPrinter, self).__init__(enum_type) + self.initialized = False + + def __call__(self, val): + if not self.initialized: + self.initialized = True + flags = gdb.lookup_type(self.name) + self.enumerators = [] + for field in flags.fields(): + self.enumerators.append((field.name, field.enumval)) + # Sorting the enumerators by value usually does the right + # thing. + self.enumerators.sort(key = lambda x: x.enumval) + + if self.enabled: + return _EnumInstance(self.enumerators, val) + else: + return None diff --git a/contrib/gdb-7/gdb/python/lib/gdb/prompt.py b/contrib/gdb-7/gdb/python/lib/gdb/prompt.py index 1f49b54888..bb1975bb83 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/prompt.py +++ b/contrib/gdb-7/gdb/python/lib/gdb/prompt.py @@ -1,5 +1,5 @@ # Extended prompt utilities. -# Copyright (C) 2011-2012 Free Software Foundation, Inc. +# Copyright (C) 2011-2013 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 @@ -98,8 +98,7 @@ def prompt_help(): functions.""" result = '' - keys = prompt_substitutions.keys() - keys.sort() + keys = sorted (prompt_substitutions.keys()) for key in keys: result += ' \\%s\t%s\n' % (key, prompt_substitutions[key].__doc__) result += """ diff --git a/contrib/gdb-7/gdb/python/lib/gdb/types.py b/contrib/gdb-7/gdb/python/lib/gdb/types.py index aca84f3f66..ffc817cd07 100644 --- a/contrib/gdb-7/gdb/python/lib/gdb/types.py +++ b/contrib/gdb-7/gdb/python/lib/gdb/types.py @@ -1,5 +1,5 @@ # Type utilities. -# Copyright (C) 2010-2012 Free Software Foundation, Inc. +# Copyright (C) 2010-2013 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 @@ -86,8 +86,8 @@ def make_enum_dict(enum_type): raise TypeError("not an enum type") enum_dict = {} for field in enum_type.fields(): - # The enum's value is stored in "bitpos". - enum_dict[field.name] = field.bitpos + # The enum's value is stored in "enumval". + enum_dict[field.name] = field.enumval return enum_dict @@ -109,3 +109,68 @@ def deep_items (type_): else: for i in deep_items (v.type): yield i + +class TypePrinter(object): + """The base class for type printers. + + Instances of this type can be used to substitute type names during + 'ptype'. + + A type printer must have at least 'name' and 'enabled' attributes, + and supply an 'instantiate' method. + + The 'instantiate' method must either return None, or return an + object which has a 'recognize' method. This method must accept a + gdb.Type argument and either return None, meaning that the type + was not recognized, or a string naming the type. + """ + + def __init__(self, name): + self.name = name + self.enabled = True + + def instantiate(self): + return None + +# Helper function for computing the list of type recognizers. +def _get_some_type_recognizers(result, plist): + for printer in plist: + if printer.enabled: + inst = printer.instantiate() + if inst is not None: + result.append(inst) + return None + +def get_type_recognizers(): + "Return a list of the enabled type recognizers for the current context." + result = [] + + # First try the objfiles. + for objfile in gdb.objfiles(): + _get_some_type_recognizers(result, objfile.type_printers) + # Now try the program space. + _get_some_type_recognizers(result, gdb.current_progspace().type_printers) + # Finally, globals. + _get_some_type_recognizers(result, gdb.type_printers) + + return result + +def apply_type_recognizers(recognizers, type_obj): + """Apply the given list of type recognizers to the type TYPE_OBJ. + If any recognizer in the list recognizes TYPE_OBJ, returns the name + given by the recognizer. Otherwise, this returns None.""" + for r in recognizers: + result = r.recognize(type_obj) + if result is not None: + return result + return None + +def register_type_printer(locus, printer): + """Register a type printer. + PRINTER is the type printer instance. + LOCUS is either an objfile, a program space, or None, indicating + global registration.""" + + if locus is None: + locus = gdb + locus.type_printers.insert(0, printer) diff --git a/contrib/gdb-7/gdb/python/py-arch.c b/contrib/gdb-7/gdb/python/py-arch.c new file mode 100644 index 0000000000..ddfebdb2f7 --- /dev/null +++ b/contrib/gdb-7/gdb/python/py-arch.c @@ -0,0 +1,294 @@ +/* Python interface to architecture + + Copyright (C) 2013 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 "gdbarch.h" +#include "arch-utils.h" +#include "disasm.h" +#include "python-internal.h" + +typedef struct arch_object_type_object { + PyObject_HEAD + struct gdbarch *gdbarch; +} arch_object; + +static struct gdbarch_data *arch_object_data = NULL; +static PyTypeObject arch_object_type; + +/* Associates an arch_object with GDBARCH as gdbarch_data via the gdbarch + post init registration mechanism (gdbarch_data_register_post_init). */ + +static void * +arch_object_data_init (struct gdbarch *gdbarch) +{ + arch_object *arch_obj = PyObject_New (arch_object, &arch_object_type); + + if (arch_obj == NULL) + return NULL; + + arch_obj->gdbarch = gdbarch; + + return (void *) arch_obj; +} + +/* Returns the struct gdbarch value corresponding to the given Python + architecture object OBJ. */ + +struct gdbarch * +arch_object_to_gdbarch (PyObject *obj) +{ + arch_object *py_arch = (arch_object *) obj; + + return py_arch->gdbarch; +} + +/* Returns the Python architecture object corresponding to GDBARCH. + Returns a new reference to the arch_object associated as data with + GDBARCH. */ + +PyObject * +gdbarch_to_arch_object (struct gdbarch *gdbarch) +{ + PyObject *new_ref = (PyObject *) gdbarch_data (gdbarch, arch_object_data); + + /* new_ref could be NULL if registration of arch_object with GDBARCH failed + in arch_object_data_init. */ + Py_XINCREF (new_ref); + + return new_ref; +} + +/* Implementation of gdb.Architecture.name (self) -> String. + Returns the name of the architecture as a string value. */ + +static PyObject * +archpy_name (PyObject *self, PyObject *args) +{ + struct gdbarch *gdbarch = arch_object_to_gdbarch (self); + const char *name = (gdbarch_bfd_arch_info (gdbarch))->printable_name; + PyObject *py_name = PyString_FromString (name); + + return py_name; +} + +/* Implementation of + gdb.Architecture.disassemble (self, start_pc [, end_pc [,count]]) -> List. + Returns a list of instructions in a memory address range. Each instruction + in the list is a Python dict object. +*/ + +static PyObject * +archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw) +{ + static char *keywords[] = { "start_pc", "end_pc", "count", NULL }; + CORE_ADDR start, end = 0; + CORE_ADDR pc; + gdb_py_ulongest start_temp; + long count = 0, i; + PyObject *result_list, *end_obj = NULL, *count_obj = NULL; + struct gdbarch *gdbarch = arch_object_to_gdbarch (self); + + if (!PyArg_ParseTupleAndKeywords (args, kw, GDB_PY_LLU_ARG "|OO", keywords, + &start_temp, &end_obj, &count_obj)) + return NULL; + + start = start_temp; + if (end_obj) + { + if (PyLong_Check (end_obj)) + end = PyLong_AsUnsignedLongLong (end_obj); + else if (PyInt_Check (end_obj)) + /* If the end_pc value is specified without a trailing 'L', end_obj will + be an integer and not a long integer. */ + end = PyInt_AsLong (end_obj); + else + { + Py_DECREF (end_obj); + Py_XDECREF (count_obj); + PyErr_SetString (PyExc_TypeError, + _("Argument 'end_pc' should be a (long) integer.")); + + return NULL; + } + + if (end < start) + { + Py_DECREF (end_obj); + Py_XDECREF (count_obj); + PyErr_SetString (PyExc_ValueError, + _("Argument 'end_pc' should be greater than or " + "equal to the argument 'start_pc'.")); + + return NULL; + } + } + if (count_obj) + { + count = PyInt_AsLong (count_obj); + if (PyErr_Occurred () || count < 0) + { + Py_DECREF (count_obj); + Py_XDECREF (end_obj); + PyErr_SetString (PyExc_TypeError, + _("Argument 'count' should be an non-negative " + "integer.")); + + return NULL; + } + } + + result_list = PyList_New (0); + if (result_list == NULL) + return NULL; + + for (pc = start, i = 0; + /* All args are specified. */ + (end_obj && count_obj && pc <= end && i < count) + /* end_pc is specified, but no count. */ + || (end_obj && count_obj == NULL && pc <= end) + /* end_pc is not specified, but a count is. */ + || (end_obj == NULL && count_obj && i < count) + /* Both end_pc and count are not specified. */ + || (end_obj == NULL && count_obj == NULL && pc == start);) + { + int insn_len = 0; + char *as = NULL; + struct ui_file *memfile = mem_fileopen (); + PyObject *insn_dict = PyDict_New (); + volatile struct gdb_exception except; + + if (insn_dict == NULL) + { + Py_DECREF (result_list); + ui_file_delete (memfile); + + return NULL; + } + if (PyList_Append (result_list, insn_dict)) + { + Py_DECREF (result_list); + Py_DECREF (insn_dict); + ui_file_delete (memfile); + + return NULL; /* PyList_Append Sets the exception. */ + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + insn_len = gdb_print_insn (gdbarch, pc, memfile, NULL); + } + if (except.reason < 0) + { + Py_DECREF (result_list); + ui_file_delete (memfile); + + return gdbpy_convert_exception (except); + } + + as = ui_file_xstrdup (memfile, NULL); + if (PyDict_SetItemString (insn_dict, "addr", + gdb_py_long_from_ulongest (pc)) + || PyDict_SetItemString (insn_dict, "asm", + PyString_FromString (*as ? as : "")) + || PyDict_SetItemString (insn_dict, "length", + PyInt_FromLong (insn_len))) + { + Py_DECREF (result_list); + + ui_file_delete (memfile); + xfree (as); + + return NULL; + } + + pc += insn_len; + i++; + ui_file_delete (memfile); + xfree (as); + } + + return result_list; +} + +/* Initializes the Architecture class in the gdb module. */ + +void +gdbpy_initialize_arch (void) +{ + arch_object_data = gdbarch_data_register_post_init (arch_object_data_init); + arch_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&arch_object_type) < 0) + return; + + Py_INCREF (&arch_object_type); + PyModule_AddObject (gdb_module, "Architecture", + (PyObject *) &arch_object_type); +} + +static PyMethodDef arch_object_methods [] = { + { "name", archpy_name, METH_NOARGS, + "name () -> String.\n\ +Return the name of the architecture as a string value." }, + { "disassemble", (PyCFunction) archpy_disassemble, + METH_VARARGS | METH_KEYWORDS, + "disassemble (start_pc [, end_pc [, count]]) -> List.\n\ +Return a list of at most COUNT disassembled instructions from START_PC to\n\ +END_PC." }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject arch_object_type = { + PyVarObject_HEAD_INIT (NULL, 0) + "gdb.Architecture", /* tp_name */ + sizeof (arch_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 architecture object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + arch_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 */ +}; diff --git a/contrib/gdb-7/gdb/python/py-auto-load.c b/contrib/gdb-7/gdb/python/py-auto-load.c index 3abb82a15c..a8cb79cfbd 100644 --- a/contrib/gdb-7/gdb/python/py-auto-load.c +++ b/contrib/gdb-7/gdb/python/py-auto-load.c @@ -1,6 +1,6 @@ /* GDB routines for supporting auto-loaded scripts. - Copyright (C) 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -18,213 +18,72 @@ along with this program. If not, see . */ #include "defs.h" -#include "filenames.h" #include "gdb_string.h" -#include "gdb_regex.h" #include "top.h" #include "exceptions.h" -#include "command.h" #include "gdbcmd.h" -#include "observer.h" -#include "progspace.h" #include "objfiles.h" #include "python.h" #include "cli/cli-cmds.h" - -/* Internal-use flag to enable/disable auto-loading. - This is true if we should auto-load python code when an objfile is opened, - false otherwise. - - Both auto_load_scripts && gdbpy_global_auto_load must be true to enable - auto-loading. - - This flag exists to facilitate deferring auto-loading during start-up - until after ./.gdbinit has been read; it may augment the search directories - used to find the scripts. */ -int gdbpy_global_auto_load = 1; +#include "auto-load.h" #ifdef HAVE_PYTHON #include "python-internal.h" -/* NOTE: It's trivial to also support auto-loading normal gdb scripts. - There has yet to be a need so it's not implemented. */ - -/* The suffix of per-objfile scripts to auto-load. - E.g. When the program loads libfoo.so, look for libfoo-gdb.py. */ -#define GDBPY_AUTO_FILE_NAME "-gdb.py" - -/* The section to look for scripts (in file formats that support sections). +/* The section to look for Python auto-loaded scripts (in file formats that + support sections). Each entry in this section is a byte of value 1, and then the nul-terminated name of the script. The script name may include a directory. The leading byte is to allow upward compatible extensions. */ #define GDBPY_AUTO_SECTION_NAME ".debug_gdb_scripts" -/* For scripts specified in .debug_gdb_scripts, multiple objfiles may load - the same script. There's no point in loading the script multiple times, - and there can be a lot of objfiles and scripts, so we keep track of scripts - loaded this way. */ +/* User-settable option to enable/disable auto-loading of Python scripts: + set auto-load python-scripts on|off + This is true if we should auto-load associated Python scripts when an + objfile is opened, false otherwise. */ +static int auto_load_python_scripts = 1; -struct auto_load_pspace_info -{ - /* For each program space we keep track of loaded scripts. */ - struct htab *loaded_scripts; - - /* Non-zero if we've issued the warning about an auto-load script not being - found. We only want to issue this warning once. */ - int script_not_found_warning_printed; -}; +static void gdbpy_load_auto_script_for_objfile (struct objfile *objfile, + FILE *file, + const char *filename); -/* Objects of this type are stored in the loaded script hash table. */ - -struct loaded_script -{ - /* Name as provided by the objfile. */ - const char *name; - /* Full path name or NULL if script wasn't found (or was otherwise - inaccessible). */ - const char *full_path; -}; - -/* User-settable option to enable/disable auto-loading: - set auto-load-scripts on|off - This is true if we should auto-load associated scripts when an objfile - is opened, false otherwise. - At the moment, this only affects python scripts, but there's no reason - one couldn't also have other kinds of auto-loaded scripts, and there's - no reason to have them each controlled by a separate flag. - So we elide "python" from the name here and in the option. - The fact that it lives here is just an implementation detail. */ -static int auto_load_scripts = 1; - -/* Per-program-space data key. */ -static const struct program_space_data *auto_load_pspace_data; +/* "show" command for the auto_load_python_scripts configuration variable. */ static void -auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg) -{ - struct auto_load_pspace_info *info; - - info = program_space_data (pspace, auto_load_pspace_data); - if (info != NULL) - { - if (info->loaded_scripts) - htab_delete (info->loaded_scripts); - xfree (info); - } -} - -/* Get the current autoload data. If none is found yet, add it now. This - function always returns a valid object. */ - -static struct auto_load_pspace_info * -get_auto_load_pspace_data (struct program_space *pspace) -{ - struct auto_load_pspace_info *info; - - info = program_space_data (pspace, auto_load_pspace_data); - if (info == NULL) - { - info = XZALLOC (struct auto_load_pspace_info); - set_program_space_data (pspace, auto_load_pspace_data, info); - } - - return info; -} - -/* Hash function for the loaded script hash. */ - -static hashval_t -hash_loaded_script_entry (const void *data) +show_auto_load_python_scripts (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) { - const struct loaded_script *e = data; - - return htab_hash_string (e->name); + fprintf_filtered (file, _("Auto-loading of Python scripts is %s.\n"), value); } -/* Equality function for the loaded script hash. */ +/* Definition of script language for Python scripts. */ -static int -eq_loaded_script_entry (const void *a, const void *b) -{ - const struct loaded_script *ea = a; - const struct loaded_script *eb = b; +static const struct script_language script_language_python + = { GDBPY_AUTO_FILE_NAME, gdbpy_load_auto_script_for_objfile }; - return strcmp (ea->name, eb->name) == 0; -} - -/* Initialize the table to track loaded scripts. - Each entry is hashed by the full path name. */ +/* Wrapper of source_python_script_for_objfile for script_language_python. */ static void -init_loaded_scripts_info (struct auto_load_pspace_info *pspace_info) -{ - /* Choose 31 as the starting size of the hash table, somewhat arbitrarily. - Space for each entry is obtained with one malloc so we can free them - easily. */ - - pspace_info->loaded_scripts = htab_create (31, - hash_loaded_script_entry, - eq_loaded_script_entry, - xfree); - - pspace_info->script_not_found_warning_printed = FALSE; -} - -/* Wrapper on get_auto_load_pspace_data to also allocate the hash table - for loading scripts. */ - -static struct auto_load_pspace_info * -get_auto_load_pspace_data_for_loading (struct program_space *pspace) -{ - struct auto_load_pspace_info *info; - - info = get_auto_load_pspace_data (pspace); - if (info->loaded_scripts == NULL) - init_loaded_scripts_info (info); - - return info; -} - -/* Add script NAME to hash table HTAB. - FULL_PATH is NULL if the script wasn't found. - The result is true if the script was already in the hash table. */ - -static int -maybe_add_script (struct htab *htab, const char *name, const char *full_path) +gdbpy_load_auto_script_for_objfile (struct objfile *objfile, FILE *file, + const char *filename) { - struct loaded_script **slot, entry; - int in_hash_table; - - entry.name = name; - entry.full_path = full_path; - slot = (struct loaded_script **) htab_find_slot (htab, &entry, INSERT); - in_hash_table = *slot != NULL; + int is_safe; + struct auto_load_pspace_info *pspace_info; - /* If this script is not in the hash table, add it. */ + is_safe = file_is_auto_load_safe (filename, + _("auto-load: Loading Python script \"%s\" " + "by extension for objfile \"%s\".\n"), + filename, objfile->name); - if (! in_hash_table) - { - char *p; - - /* Allocate all space in one chunk so it's easier to free. */ - *slot = xmalloc (sizeof (**slot) - + strlen (name) + 1 - + (full_path != NULL ? (strlen (full_path) + 1) : 0)); - p = ((char*) *slot) + sizeof (**slot); - strcpy (p, name); - (*slot)->name = p; - if (full_path != NULL) - { - p += strlen (p) + 1; - strcpy (p, full_path); - (*slot)->full_path = p; - } - else - (*slot)->full_path = NULL; - } + /* Add this script to the hash table too so "info auto-load python-scripts" + can print it. */ + pspace_info = get_auto_load_pspace_data_for_loading (current_program_space); + maybe_add_script (pspace_info, is_safe, filename, filename, + &script_language_python); - return in_hash_table; + if (is_safe) + source_python_script_for_objfile (objfile, file, filename); } /* Load scripts specified in OBJFILE. @@ -254,6 +113,7 @@ source_section_scripts (struct objfile *objfile, const char *source_name, FILE *stream; char *full_path; int opened, in_hash_table; + struct cleanup *back_to; if (*p != 1) { @@ -286,6 +146,32 @@ source_section_scripts (struct objfile *objfile, const char *source_name, opened = find_and_open_script (file, 1 /*search_path*/, &stream, &full_path); + back_to = make_cleanup (null_cleanup, NULL); + if (opened) + { + make_cleanup_fclose (stream); + make_cleanup (xfree, full_path); + + if (!file_is_auto_load_safe (full_path, + _("auto-load: Loading Python script " + "\"%s\" from section \"%s\" of " + "objfile \"%s\".\n"), + full_path, GDBPY_AUTO_SECTION_NAME, + objfile->name)) + opened = 0; + } + else + { + full_path = NULL; + + /* We don't throw an error, the program is still debuggable. */ + if (script_not_found_warning_print (pspace_info)) + warning (_("Missing auto-load scripts referenced in section %s\n\ +of file %s\n\ +Use `info auto-load python [REGEXP]' to list them."), + GDBPY_AUTO_SECTION_NAME, objfile->name); + } + /* If one script isn't found it's not uncommon for more to not be found either. We don't want to print an error message for each script, too much noise. Instead, we print the warning once and tell @@ -293,29 +179,14 @@ source_section_scripts (struct objfile *objfile, const char *source_name, IWBN if complaints.c were more general-purpose. */ - in_hash_table = maybe_add_script (pspace_info->loaded_scripts, file, - opened ? full_path : NULL); + in_hash_table = maybe_add_script (pspace_info, opened, file, full_path, + &script_language_python); - if (! opened) - { - /* We don't throw an error, the program is still debuggable. */ - if (! pspace_info->script_not_found_warning_printed) - { - warning (_("Missing auto-load scripts referenced in section %s\n\ -of file %s\n\ -Use `info auto-load-scripts [REGEXP]' to list them."), - GDBPY_AUTO_SECTION_NAME, objfile->name); - pspace_info->script_not_found_warning_printed = TRUE; - } - } - else - { - /* If this file is not currently loaded, load it. */ - if (! in_hash_table) - source_python_script_for_objfile (objfile, full_path); - fclose (stream); - xfree (full_path); - } + /* If this file is not currently loaded, load it. */ + if (opened && !in_hash_table) + source_python_script_for_objfile (objfile, stream, full_path); + + do_cleanups (back_to); } } @@ -326,309 +197,96 @@ auto_load_section_scripts (struct objfile *objfile, const char *section_name) { bfd *abfd = objfile->obfd; asection *scripts_sect; - bfd_size_type size; - char *p; - struct cleanup *cleanups; + bfd_byte *data = NULL; scripts_sect = bfd_get_section_by_name (abfd, section_name); if (scripts_sect == NULL) return; - size = bfd_get_section_size (scripts_sect); - p = xmalloc (size); - - cleanups = make_cleanup (xfree, p); - - if (bfd_get_section_contents (abfd, scripts_sect, p, (file_ptr) 0, size)) - source_section_scripts (objfile, section_name, p, p + size); - else + if (!bfd_get_full_section_contents (abfd, scripts_sect, &data)) warning (_("Couldn't read %s section of %s"), section_name, bfd_get_filename (abfd)); - - do_cleanups (cleanups); -} - -/* Clear the table of loaded section scripts. */ - -static void -clear_section_scripts (void) -{ - struct program_space *pspace = current_program_space; - struct auto_load_pspace_info *info; - - info = program_space_data (pspace, auto_load_pspace_data); - if (info != NULL && info->loaded_scripts != NULL) - { - htab_delete (info->loaded_scripts); - info->loaded_scripts = NULL; - info->script_not_found_warning_printed = FALSE; - } -} - -/* Look for the auto-load script associated with OBJFILE and load it. */ - -static void -auto_load_objfile_script (struct objfile *objfile, const char *suffix) -{ - char *realname; - char *filename, *debugfile; - int len; - FILE *input; - struct cleanup *cleanups; - - realname = gdb_realpath (objfile->name); - len = strlen (realname); - filename = xmalloc (len + strlen (suffix) + 1); - memcpy (filename, realname, len); - strcpy (filename + len, suffix); - - cleanups = make_cleanup (xfree, filename); - make_cleanup (xfree, realname); - - input = fopen (filename, "r"); - debugfile = filename; - - 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) + else { - struct auto_load_pspace_info *pspace_info; - - /* Add this script to the hash table too so "info auto-load-scripts" - can print it. */ - pspace_info = - get_auto_load_pspace_data_for_loading (current_program_space); - maybe_add_script (pspace_info->loaded_scripts, debugfile, debugfile); - - /* To preserve existing behaviour we don't check for whether the - script was already in the table, and always load it. - It's highly unlikely that we'd ever load it twice, - and these scripts are required to be idempotent under multiple - loads anyway. */ - source_python_script_for_objfile (objfile, debugfile); - fclose (input); - } - - do_cleanups (cleanups); -} + struct cleanup *cleanups; + char *p = (char *) data; -/* This is a new_objfile observer callback to auto-load scripts. - - Two flavors of auto-loaded scripts are supported. - 1) based on the path to the objfile - 2) from .debug_gdb_scripts section */ - -static void -auto_load_new_objfile (struct objfile *objfile) -{ - if (!objfile) - { - /* OBJFILE is NULL when loading a new "main" symbol-file. */ - clear_section_scripts (); - return; + cleanups = make_cleanup (xfree, p); + source_section_scripts (objfile, section_name, p, + p + bfd_get_section_size (scripts_sect)); + do_cleanups (cleanups); } - - load_auto_scripts_for_objfile (objfile); } -/* Load any auto-loaded scripts for OBJFILE. */ +/* Load any Python auto-loaded scripts for OBJFILE. */ void -load_auto_scripts_for_objfile (struct objfile *objfile) +gdbpy_load_auto_scripts_for_objfile (struct objfile *objfile) { - if (auto_load_scripts && gdbpy_global_auto_load) + if (auto_load_python_scripts) { - auto_load_objfile_script (objfile, GDBPY_AUTO_FILE_NAME); + auto_load_objfile_script (objfile, &script_language_python); auto_load_section_scripts (objfile, GDBPY_AUTO_SECTION_NAME); } } - -/* Collect scripts to be printed in a vec. */ - -typedef struct loaded_script *loaded_script_ptr; -DEF_VEC_P (loaded_script_ptr); -/* Traversal function for htab_traverse. - Collect the entry if it matches the regexp. */ - -static int -collect_matching_scripts (void **slot, void *info) -{ - struct loaded_script *script = *slot; - VEC (loaded_script_ptr) **scripts_ptr = info; - - if (re_exec (script->name)) - VEC_safe_push (loaded_script_ptr, *scripts_ptr, script); - - return 1; -} - -/* Print SCRIPT. */ +/* Wrapper for "info auto-load python-scripts". */ static void -print_script (struct loaded_script *script) +info_auto_load_python_scripts (char *pattern, int from_tty) { - struct ui_out *uiout = current_uiout; - struct cleanup *chain; - - chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - - ui_out_field_string (uiout, "loaded", script->full_path ? "Yes" : "Missing"); - ui_out_field_string (uiout, "script", script->name); - ui_out_text (uiout, "\n"); - - /* If the name isn't the full path, print it too. */ - if (script->full_path != NULL - && strcmp (script->name, script->full_path) != 0) - { - ui_out_text (uiout, "\tfull name: "); - ui_out_field_string (uiout, "full_path", script->full_path); - ui_out_text (uiout, "\n"); - } - - do_cleanups (chain); -} - -/* Helper for info_auto_load_scripts to sort the scripts by name. */ - -static int -sort_scripts_by_name (const void *ap, const void *bp) -{ - const struct loaded_script *a = *(const struct loaded_script **) ap; - const struct loaded_script *b = *(const struct loaded_script **) bp; - - return FILENAME_CMP (a->name, b->name); -} - -/* "info auto-load-scripts" command. */ - -static void -info_auto_load_scripts (char *pattern, int from_tty) -{ - struct ui_out *uiout = current_uiout; - struct auto_load_pspace_info *pspace_info; - struct cleanup *script_chain; - VEC (loaded_script_ptr) *scripts; - int nr_scripts; - - dont_repeat (); - - pspace_info = get_auto_load_pspace_data (current_program_space); - - if (pattern && *pattern) - { - char *re_err = re_comp (pattern); - - if (re_err) - error (_("Invalid regexp: %s"), re_err); - } - else - { - re_comp (""); - } - - /* We need to know the number of rows before we build the table. - Plus we want to sort the scripts by name. - So first traverse the hash table collecting the matching scripts. */ - - scripts = VEC_alloc (loaded_script_ptr, 10); - script_chain = make_cleanup (VEC_cleanup (loaded_script_ptr), &scripts); - - if (pspace_info != NULL && pspace_info->loaded_scripts != NULL) - { - immediate_quit++; - /* Pass a pointer to scripts as VEC_safe_push can realloc space. */ - htab_traverse_noresize (pspace_info->loaded_scripts, - collect_matching_scripts, &scripts); - immediate_quit--; - } - - nr_scripts = VEC_length (loaded_script_ptr, scripts); - make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, - "AutoLoadedScriptsTable"); - - ui_out_table_header (uiout, 7, ui_left, "loaded", "Loaded"); - ui_out_table_header (uiout, 70, ui_left, "script", "Script"); - ui_out_table_body (uiout); - - if (nr_scripts > 0) - { - int i; - loaded_script_ptr script; - - qsort (VEC_address (loaded_script_ptr, scripts), - VEC_length (loaded_script_ptr, scripts), - sizeof (loaded_script_ptr), sort_scripts_by_name); - for (i = 0; VEC_iterate (loaded_script_ptr, scripts, i, script); ++i) - print_script (script); - } - - do_cleanups (script_chain); - - if (nr_scripts == 0) - { - if (pattern && *pattern) - ui_out_message (uiout, 0, "No auto-load scripts matching %s.\n", - pattern); - else - ui_out_message (uiout, 0, "No auto-load scripts.\n"); - } + auto_load_info_scripts (pattern, from_tty, &script_language_python); } void gdbpy_initialize_auto_load (void) { - auto_load_pspace_data - = register_program_space_data_with_cleanup (auto_load_pspace_data_cleanup); - - observer_attach_new_objfile (auto_load_new_objfile); + struct cmd_list_element *cmd; + char *cmd_name; + + add_setshow_boolean_cmd ("python-scripts", class_support, + &auto_load_python_scripts, _("\ +Set the debugger's behaviour regarding auto-loaded Python scripts."), _("\ +Show the debugger's behaviour regarding auto-loaded Python scripts."), _("\ +If enabled, auto-loaded Python scripts are loaded when the debugger reads\n\ +an executable or shared library.\n\ +This options has security implications for untrusted inferiors."), + NULL, show_auto_load_python_scripts, + auto_load_set_cmdlist_get (), + auto_load_show_cmdlist_get ()); add_setshow_boolean_cmd ("auto-load-scripts", class_support, - &auto_load_scripts, _("\ -Set the debugger's behaviour regarding auto-loaded scripts."), _("\ -Show the debugger's behaviour regarding auto-loaded scripts."), _("\ -If enabled, auto-loaded scripts are loaded when the debugger reads\n\ -an executable or shared library."), - NULL, NULL, - &setlist, - &showlist); - - add_info ("auto-load-scripts", - info_auto_load_scripts, - _("Print the list of automatically loaded scripts.\n\ -Usage: info auto-load-scripts [REGEXP]")); + &auto_load_python_scripts, _("\ +Set the debugger's behaviour regarding auto-loaded Python scripts, " + "deprecated."), + _("\ +Show the debugger's behaviour regarding auto-loaded Python scripts, " + "deprecated."), + NULL, NULL, show_auto_load_python_scripts, + &setlist, &showlist); + cmd_name = "auto-load-scripts"; + cmd = lookup_cmd (&cmd_name, setlist, "", -1, 1); + deprecate_cmd (cmd, "set auto-load python-scripts"); + + /* It is needed because lookup_cmd updates the CMD_NAME pointer. */ + cmd_name = "auto-load-scripts"; + cmd = lookup_cmd (&cmd_name, showlist, "", -1, 1); + deprecate_cmd (cmd, "show auto-load python-scripts"); + + add_cmd ("python-scripts", class_info, info_auto_load_python_scripts, + _("Print the list of automatically loaded Python scripts.\n\ +Usage: info auto-load python-scripts [REGEXP]"), + auto_load_info_cmdlist_get ()); + + cmd = add_info ("auto-load-scripts", info_auto_load_python_scripts, _("\ +Print the list of automatically loaded Python scripts, deprecated.")); + deprecate_cmd (cmd, "info auto-load python-scripts"); } #else /* ! HAVE_PYTHON */ void -load_auto_scripts_for_objfile (struct objfile *objfile) +gdbpy_load_auto_scripts_for_objfile (struct objfile *objfile) { } diff --git a/contrib/gdb-7/gdb/python/py-block.c b/contrib/gdb-7/gdb/python/py-block.c index ac48193121..f0b8322270 100644 --- a/contrib/gdb-7/gdb/python/py-block.c +++ b/contrib/gdb-7/gdb/python/py-block.c @@ -1,6 +1,6 @@ /* Python interface to blocks. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -41,10 +41,10 @@ typedef struct blpy_block_object { typedef struct { PyObject_HEAD - /* The block dictionary of symbols. */ - struct dictionary *dict; - /* The iterator for that dictionary. */ - struct dict_iterator iter; + /* The block. */ + const struct block *block; + /* The iterator for that block. */ + struct block_iterator iter; /* Has the iterator been initialized flag. */ int initialized_p; /* Pointer back to the original source block object. Needed to @@ -94,7 +94,7 @@ blpy_iter (PyObject *self) if (block_iter_obj == NULL) return NULL; - block_iter_obj->dict = BLOCK_DICT (block); + block_iter_obj->block = block; block_iter_obj->initialized_p = 0; Py_INCREF (self); block_iter_obj->source = (block_object *) self; @@ -311,11 +311,11 @@ blpy_block_syms_iternext (PyObject *self) if (!iter_obj->initialized_p) { - sym = dict_iterator_first (iter_obj->dict, &(iter_obj->iter)); + sym = block_iterator_first (iter_obj->block, &(iter_obj->iter)); iter_obj->initialized_p = 1; } else - sym = dict_iterator_next (&(iter_obj->iter)); + sym = block_iterator_next (&(iter_obj->iter)); if (sym == NULL) { @@ -370,7 +370,7 @@ PyObject * gdbpy_block_for_pc (PyObject *self, PyObject *args) { gdb_py_ulongest pc; - struct block *block; + struct block *block = NULL; struct obj_section *section = NULL; struct symtab *symtab = NULL; volatile struct gdb_exception except; @@ -382,6 +382,9 @@ gdbpy_block_for_pc (PyObject *self, PyObject *args) { section = find_pc_mapped_section (pc); symtab = find_pc_sect_symtab (pc, section); + + if (symtab != NULL && symtab->objfile != NULL) + block = block_for_pc (pc); } GDB_PY_HANDLE_EXCEPTION (except); @@ -392,7 +395,6 @@ gdbpy_block_for_pc (PyObject *self, PyObject *args) return NULL; } - block = block_for_pc (pc); if (block) return block_to_block_object (block, symtab->objfile); @@ -475,8 +477,7 @@ static PyGetSetDef block_object_getset[] = { }; PyTypeObject block_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Block", /*tp_name*/ sizeof (block_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ @@ -516,8 +517,7 @@ Return true if this block iterator is valid, false if not." }, }; static PyTypeObject block_syms_iterator_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.BlockIterator", /*tp_name*/ sizeof (block_syms_iterator_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-bpevent.c b/contrib/gdb-7/gdb/python/py-bpevent.c index 138c39f0b2..dad93dc8df 100644 --- a/contrib/gdb-7/gdb/python/py-bpevent.c +++ b/contrib/gdb-7/gdb/python/py-bpevent.c @@ -1,6 +1,6 @@ /* Python interface to inferior breakpoint stop events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,11 +17,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-stopevent.h" static PyTypeObject breakpoint_event_object_type; -/* Create and initialize a BreakpointEvent object. */ +/* Create and initialize a BreakpointEvent object. This acquires new + references to BREAKPOINT_LIST and FIRST_BP. */ PyObject * create_breakpoint_event_object (PyObject *breakpoint_list, PyObject *first_bp) diff --git a/contrib/gdb-7/gdb/python/py-breakpoint.c b/contrib/gdb-7/gdb/python/py-breakpoint.c index 0c84d03b0a..5e5f9b33a1 100644 --- a/contrib/gdb-7/gdb/python/py-breakpoint.c +++ b/contrib/gdb-7/gdb/python/py-breakpoint.c @@ -1,6 +1,6 @@ /* Python interface to breakpoints - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -21,6 +21,7 @@ #include "value.h" #include "exceptions.h" #include "python-internal.h" +#include "python.h" #include "charset.h" #include "breakpoint.h" #include "gdbcmd.h" @@ -47,7 +48,7 @@ struct pybp_code /* The name. */ const char *name; /* The code. */ - enum type_code code; + int code; }; /* Entries related to the type of user set breakpoints. */ @@ -621,7 +622,7 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs) case bp_breakpoint: { create_breakpoint (python_gdbarch, - copy, NULL, -1, + copy, NULL, -1, NULL, 0, 0, bp_breakpoint, 0, @@ -980,8 +981,7 @@ static PyMethodDef breakpoint_object_methods[] = PyTypeObject breakpoint_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Breakpoint", /*tp_name*/ sizeof (breakpoint_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-cmd.c b/contrib/gdb-7/gdb/python/py-cmd.c index aad1ab466c..76670eafe3 100644 --- a/contrib/gdb-7/gdb/python/py-cmd.c +++ b/contrib/gdb-7/gdb/python/py-cmd.c @@ -1,6 +1,6 @@ /* gdb commands implemented in Python - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -35,7 +35,7 @@ struct cmdpy_completer /* Python symbol name. */ char *name; /* Completion function. */ - char **(*completer) (struct cmd_list_element *, char *, char *); + completer_ftype *completer; }; static struct cmdpy_completer completers[] = @@ -206,12 +206,12 @@ cmdpy_function (struct cmd_list_element *command, char *args, int from_tty) /* Called by gdb for command completion. */ -static char ** +static VEC (char_ptr) * cmdpy_completer (struct cmd_list_element *command, char *text, char *word) { cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command); PyObject *textobj, *wordobj, *resultobj = NULL; - char **result = NULL; + VEC (char_ptr) *result = NULL; struct cleanup *cleanup; cleanup = ensure_python_env (get_current_arch (), current_language); @@ -253,10 +253,10 @@ cmdpy_completer (struct cmd_list_element *command, char *text, char *word) if (len < 0) goto done; - result = (char **) xmalloc ((len + 1) * sizeof (char *)); for (i = out = 0; i < len; ++i) { PyObject *elt = PySequence_GetItem (resultobj, i); + char *item; if (elt == NULL || ! gdbpy_is_string (elt)) { @@ -264,16 +264,15 @@ cmdpy_completer (struct cmd_list_element *command, char *text, char *word) PyErr_Clear (); continue; } - result[out] = python_string_to_host_string (elt); - if (result[out] == NULL) + item = python_string_to_host_string (elt); + if (item == NULL) { /* Skip problem elements. */ PyErr_Clear (); continue; } - ++out; + VEC_safe_push (char_ptr, result, item); } - result[out] = NULL; } else if (PyInt_Check (resultobj)) { @@ -436,7 +435,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw) && cmdtype != class_files && cmdtype != class_support && cmdtype != class_info && cmdtype != class_breakpoint && cmdtype != class_trace && cmdtype != class_obscure - && cmdtype != class_maintenance) + && cmdtype != class_maintenance && cmdtype != class_user) { PyErr_Format (PyExc_RuntimeError, _("Invalid command class argument.")); return -1; @@ -578,7 +577,8 @@ gdbpy_initialize_commands (void) || PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE", class_obscure) < 0 || PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE", - class_maintenance) < 0) + class_maintenance) < 0 + || PyModule_AddIntConstant (gdb_module, "COMMAND_USER", class_user) < 0) return; for (i = 0; i < N_COMPLETERS; ++i) @@ -607,8 +607,7 @@ static PyMethodDef cmdpy_object_methods[] = static PyTypeObject cmdpy_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Command", /*tp_name*/ sizeof (cmdpy_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-continueevent.c b/contrib/gdb-7/gdb/python/py-continueevent.c index 4582fb5ab9..6412c01ae7 100644 --- a/contrib/gdb-7/gdb/python/py-continueevent.c +++ b/contrib/gdb-7/gdb/python/py-continueevent.c @@ -1,6 +1,6 @@ /* Python interface to inferior continue events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,11 +17,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-event.h" static PyTypeObject continue_event_object_type; -PyObject * +static PyObject * create_continue_event_object (void) { return create_thread_event_object (&continue_event_object_type); diff --git a/contrib/gdb-7/gdb/python/py-event.c b/contrib/gdb-7/gdb/python/py-event.c index 7d4ff14457..2c18e2fae3 100644 --- a/contrib/gdb-7/gdb/python/py-event.c +++ b/contrib/gdb-7/gdb/python/py-event.c @@ -1,6 +1,6 @@ /* Python interface to inferior events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,13 +17,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-event.h" void evpy_dealloc (PyObject *self) { Py_XDECREF (((event_object *) self)->dict); - self->ob_type->tp_free (self); + Py_TYPE (self)->tp_free (self); } PyObject * @@ -48,7 +49,8 @@ create_event_object (PyTypeObject *py_type) /* Add the attribute ATTR to the event object EVENT. In python this attribute will be accessible by the name NAME. - returns 0 if the operation succeeds and -1 otherwise. */ + returns 0 if the operation succeeds and -1 otherwise. This + function acquires a new reference to ATTR. */ int evpy_add_attribute (PyObject *event, char *name, PyObject *attr) @@ -132,10 +134,16 @@ evpy_emit_event (PyObject *event, return -1; } +static PyGetSetDef event_object_getset[] = +{ + { "__dict__", gdb_py_generic_dict, NULL, + "The __dict__ for this event.", &event_object_type }, + { NULL } +}; + PyTypeObject event_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /* ob_size */ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Event", /* tp_name */ sizeof (event_object), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -164,7 +172,7 @@ PyTypeObject event_object_type = 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + event_object_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ diff --git a/contrib/gdb-7/gdb/python/py-event.h b/contrib/gdb-7/gdb/python/py-event.h index e54c17a503..86da97435e 100644 --- a/contrib/gdb-7/gdb/python/py-event.h +++ b/contrib/gdb-7/gdb/python/py-event.h @@ -1,6 +1,6 @@ /* Python interface to inferior events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -20,7 +20,6 @@ #ifndef GDB_PY_EVENT_H #define GDB_PY_EVENT_H -#include "defs.h" #include "py-events.h" #include "command.h" #include "python-internal.h" @@ -49,8 +48,7 @@ \ qual PyTypeObject name##_event_object_type = \ { \ - PyObject_HEAD_INIT (NULL) \ - 0, /* ob_size */ \ + PyVarObject_HEAD_INIT (NULL, 0) \ py_path, /* tp_name */ \ sizeof (event_object), /* tp_basicsize */ \ 0, /* tp_itemsize */ \ diff --git a/contrib/gdb-7/gdb/python/py-events.h b/contrib/gdb-7/gdb/python/py-events.h index dbf239423e..537bcc9176 100644 --- a/contrib/gdb-7/gdb/python/py-events.h +++ b/contrib/gdb-7/gdb/python/py-events.h @@ -1,6 +1,6 @@ /* Python interface to inferior events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -20,7 +20,6 @@ #ifndef GDB_PY_EVENTS_H #define GDB_PY_EVENTS_H -#include "defs.h" #include "command.h" #include "python-internal.h" #include "inferior.h" diff --git a/contrib/gdb-7/gdb/python/py-evtregistry.c b/contrib/gdb-7/gdb/python/py-evtregistry.c index 0a2c336d93..2e338ccf5b 100644 --- a/contrib/gdb-7/gdb/python/py-evtregistry.c +++ b/contrib/gdb-7/gdb/python/py-evtregistry.c @@ -1,6 +1,6 @@ /* Python interface to inferior thread event registries. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -97,7 +97,7 @@ static void evregpy_dealloc (PyObject *self) { Py_XDECREF (((eventregistry_object *) self)->callbacks); - self->ob_type->tp_free (self); + Py_TYPE (self)->tp_free (self); } /* Initialize the Python event registry code. */ @@ -131,8 +131,7 @@ static PyMethodDef eventregistry_object_methods[] = static PyTypeObject eventregistry_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /* ob_size */ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.EventRegistry", /* tp_name */ sizeof (eventregistry_object), /* tp_basicsize */ 0, /* tp_itemsize */ diff --git a/contrib/gdb-7/gdb/python/py-evts.c b/contrib/gdb-7/gdb/python/py-evts.c index 38cd128d52..4c079e2b5b 100644 --- a/contrib/gdb-7/gdb/python/py-evts.c +++ b/contrib/gdb-7/gdb/python/py-evts.c @@ -1,6 +1,6 @@ /* Python interface to inferior events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,8 +17,24 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-events.h" +#ifdef IS_PY3K +static struct PyModuleDef EventModuleDef = +{ + PyModuleDef_HEAD_INIT, + "gdb.events", + NULL, + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; +#endif + /* Initialize python events. */ static int @@ -44,7 +60,11 @@ add_new_registry (eventregistry_object **registryp, char *name) void gdbpy_initialize_py_events (void) { +#ifdef IS_PY3K + gdb_py_events.module = PyModule_Create (&EventModuleDef); +#else gdb_py_events.module = Py_InitModule ("events", NULL); +#endif if (!gdb_py_events.module) goto fail; @@ -61,7 +81,9 @@ gdbpy_initialize_py_events (void) if (add_new_registry (&gdb_py_events.new_objfile, "new_objfile") < 0) goto fail; +#ifndef IS_PY3K Py_INCREF (gdb_py_events.module); +#endif if (PyModule_AddObject (gdb_module, "events", (PyObject *) gdb_py_events.module) < 0) diff --git a/contrib/gdb-7/gdb/python/py-exitedevent.c b/contrib/gdb-7/gdb/python/py-exitedevent.c index 272fd30395..725518bca2 100644 --- a/contrib/gdb-7/gdb/python/py-exitedevent.c +++ b/contrib/gdb-7/gdb/python/py-exitedevent.c @@ -1,6 +1,6 @@ /* Python interface to inferior exit events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-event.h" static PyTypeObject exited_event_object_type; @@ -25,30 +26,41 @@ static PyObject * create_exited_event_object (const LONGEST *exit_code, struct inferior *inf) { PyObject *exited_event; - PyObject *inf_obj; + PyObject *inf_obj = NULL; exited_event = create_event_object (&exited_event_object_type); if (!exited_event) goto fail; - if (exit_code - && evpy_add_attribute (exited_event, - "exit_code", - PyLong_FromLongLong (*exit_code)) < 0) - goto fail; + if (exit_code) + { + PyObject *exit_code_obj = PyLong_FromLongLong (*exit_code); + int failed; + + if (exit_code_obj == NULL) + goto fail; + + failed = evpy_add_attribute (exited_event, "exit_code", + exit_code_obj) < 0; + Py_DECREF (exit_code_obj); + if (failed) + goto fail; + } inf_obj = inferior_to_inferior_object (inf); if (!inf_obj || evpy_add_attribute (exited_event, "inferior", inf_obj) < 0) goto fail; + Py_DECREF (inf_obj); return exited_event; - fail: - Py_XDECREF (exited_event); - return NULL; + fail: + Py_XDECREF (inf_obj); + Py_XDECREF (exited_event); + return NULL; } /* Callback that is used when an exit event occurs. This function diff --git a/contrib/gdb-7/gdb/python/py-finishbreakpoint.c b/contrib/gdb-7/gdb/python/py-finishbreakpoint.c index e083576f8e..6e095b593f 100644 --- a/contrib/gdb-7/gdb/python/py-finishbreakpoint.c +++ b/contrib/gdb-7/gdb/python/py-finishbreakpoint.c @@ -1,6 +1,6 @@ /* Python interface to finish breakpoints - Copyright (C) 2011-2012 Free Software Foundation, Inc. + Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -29,6 +29,7 @@ #include "language.h" #include "observer.h" #include "inferior.h" +#include "block.h" static PyTypeObject finish_breakpoint_object_type; @@ -45,9 +46,9 @@ struct finish_breakpoint_object May be NULL if no debug information was available or return type was VOID. */ PyObject *return_type; - /* gdb.Type object of the function finished by this breakpoint. Will be + /* gdb.Value object of the function finished by this breakpoint. Will be NULL if return_type is NULL. */ - PyObject *function_type; + PyObject *function_value; /* When stopped at this FinishBreakpoint, gdb.Value object returned by the function; Py_None if the value is not computable; NULL if GDB is not stopped at a FinishBreakpoint. */ @@ -78,7 +79,7 @@ bpfinishpy_dealloc (PyObject *self) struct finish_breakpoint_object *self_bpfinish = (struct finish_breakpoint_object *) self; - Py_XDECREF (self_bpfinish->function_type); + Py_XDECREF (self_bpfinish->function_value); Py_XDECREF (self_bpfinish->return_type); Py_XDECREF (self_bpfinish->return_value); } @@ -102,9 +103,11 @@ bpfinishpy_pre_stop_hook (struct breakpoint_object *bp_obj) TRY_CATCH (except, RETURN_MASK_ALL) { - struct value *ret = - get_return_value (type_object_to_type (self_finishbp->function_type), - type_object_to_type (self_finishbp->return_type)); + struct value *function = + value_object_to_value (self_finishbp->function_value); + struct type *value_type = + type_object_to_type (self_finishbp->return_type); + struct value *ret = get_return_value (function, value_type); if (ret) { @@ -157,7 +160,8 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) int type = bp_breakpoint; PyObject *frame_obj = NULL; int thread; - struct frame_info *frame, *prev_frame = NULL; + struct frame_info *frame = NULL; /* init for gcc -Wall */ + struct frame_info *prev_frame = NULL; struct frame_id frame_id; PyObject *internal = NULL; int internal_bp = 0; @@ -170,39 +174,43 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) &frame_obj, &internal)) return -1; - /* Default frame to gdb.newest_frame if necessary. */ - if (!frame_obj) - frame_obj = gdbpy_newest_frame (NULL, NULL); - else - Py_INCREF (frame_obj); - - frame = frame_object_to_frame_info (frame_obj); - Py_DECREF (frame_obj); - - if (frame == NULL) - goto invalid_frame; - TRY_CATCH (except, RETURN_MASK_ALL) { - prev_frame = get_prev_frame (frame); - if (prev_frame == 0) - { - PyErr_SetString (PyExc_ValueError, _("\"FinishBreakpoint\" not " \ - "meaningful in the outermost "\ - "frame.")); - } - else if (get_frame_type (prev_frame) == DUMMY_FRAME) - { - PyErr_SetString (PyExc_ValueError, _("\"FinishBreakpoint\" cannot "\ - "be set on a dummy frame.")); - } + /* Default frame to newest frame if necessary. */ + if (frame_obj == NULL) + frame = get_current_frame (); else - { - frame_id = get_frame_id (prev_frame); - if (frame_id_eq (frame_id, null_frame_id)) - PyErr_SetString (PyExc_ValueError, - _("Invalid ID for the `frame' object.")); - } + frame = frame_object_to_frame_info (frame_obj); + + if (frame == NULL) + { + PyErr_SetString (PyExc_ValueError, + _("Invalid ID for the `frame' object.")); + } + else + { + prev_frame = get_prev_frame (frame); + if (prev_frame == 0) + { + PyErr_SetString (PyExc_ValueError, + _("\"FinishBreakpoint\" not " + "meaningful in the outermost " + "frame.")); + } + else if (get_frame_type (prev_frame) == DUMMY_FRAME) + { + PyErr_SetString (PyExc_ValueError, + _("\"FinishBreakpoint\" cannot " + "be set on a dummy frame.")); + } + else + { + frame_id = get_frame_id (prev_frame); + if (frame_id_eq (frame_id, null_frame_id)) + PyErr_SetString (PyExc_ValueError, + _("Invalid ID for the `frame' object.")); + } + } } if (except.reason < 0) { @@ -233,7 +241,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) /* Find the function we will return from. */ self_bpfinish->return_type = NULL; - self_bpfinish->function_type = NULL; + self_bpfinish->function_value = NULL; TRY_CATCH (except, RETURN_MASK_ALL) { @@ -248,25 +256,28 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) /* Remember only non-void return types. */ if (TYPE_CODE (ret_type) != TYPE_CODE_VOID) { + struct value *func_value; + /* Ignore Python errors at this stage. */ self_bpfinish->return_type = type_to_type_object (ret_type); PyErr_Clear (); - self_bpfinish->function_type = - type_to_type_object (SYMBOL_TYPE (function)); + func_value = read_var_value (function, frame); + self_bpfinish->function_value = + value_to_value_object (func_value); PyErr_Clear (); } } } } if (except.reason < 0 - || !self_bpfinish->return_type || !self_bpfinish->function_type) + || !self_bpfinish->return_type || !self_bpfinish->function_value) { /* Won't be able to compute return value. */ Py_XDECREF (self_bpfinish->return_type); - Py_XDECREF (self_bpfinish->function_type); + Py_XDECREF (self_bpfinish->function_value); self_bpfinish->return_type = NULL; - self_bpfinish->function_type = NULL; + self_bpfinish->function_value = NULL; } bppy_pending_object = &self_bpfinish->py_bp; @@ -277,11 +288,11 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) { /* Set a breakpoint on the return address. */ finish_pc = get_frame_pc (prev_frame); - sprintf (small_buf, "*%s", hex_string (finish_pc)); + xsnprintf (small_buf, sizeof (small_buf), "*%s", hex_string (finish_pc)); addr_str = small_buf; create_breakpoint (python_gdbarch, - addr_str, NULL, thread, + addr_str, NULL, thread, NULL, 0, 1 /*temp_flag*/, bp_breakpoint, @@ -299,11 +310,6 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) self_bpfinish->py_bp.bp->pspace = current_program_space; return 0; - - invalid_frame: - PyErr_SetString (PyExc_ValueError, - _("Invalid ID for the `frame' object.")); - return -1; } /* Called when GDB notices that the finish breakpoint BP_OBJ is out of @@ -313,7 +319,6 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) static void bpfinishpy_out_of_scope (struct finish_breakpoint_object *bpfinish_obj) { - volatile struct gdb_exception except; breakpoint_object *bp_obj = (breakpoint_object *) bpfinish_obj; PyObject *py_obj = (PyObject *) bp_obj; @@ -387,7 +392,7 @@ bpfinishpy_handle_stop (struct bpstats *bs, int print_frame) static void bpfinishpy_handle_exit (struct inferior *inf) { - struct cleanup *cleanup = ensure_python_env (target_gdbarch, + struct cleanup *cleanup = ensure_python_env (target_gdbarch (), current_language); iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb, NULL); @@ -420,8 +425,7 @@ None otherwise.", NULL }, static PyTypeObject finish_breakpoint_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.FinishBreakpoint", /*tp_name*/ sizeof (struct finish_breakpoint_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-frame.c b/contrib/gdb-7/gdb/python/py-frame.c index a8ce5980a8..e2eb9c5947 100644 --- a/contrib/gdb-7/gdb/python/py-frame.c +++ b/contrib/gdb-7/gdb/python/py-frame.c @@ -1,6 +1,6 @@ /* Python interface to stack frames - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -54,8 +54,6 @@ typedef struct { 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. */ @@ -124,7 +122,7 @@ static PyObject * frapy_name (PyObject *self, PyObject *args) { struct frame_info *frame; - char *name; + const char *name; enum language lang; PyObject *result; volatile struct gdb_exception except; @@ -169,6 +167,25 @@ frapy_type (PyObject *self, PyObject *args) return PyInt_FromLong (type); } +/* Implementation of gdb.Frame.architecture (self) -> gdb.Architecture. + Returns the frame's architecture as a gdb.Architecture object. */ + +static PyObject * +frapy_arch (PyObject *self, PyObject *args) +{ + struct frame_info *frame = NULL; /* Initialize to appease gcc warning. */ + frame_object *obj = (frame_object *) self; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID (self, frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return gdbarch_to_arch_object (obj->gdbarch); +} + /* Implementation of gdb.Frame.unwind_stop_reason (self) -> Integer. Returns one of the gdb.FRAME_UNWIND_* constants. */ @@ -634,6 +651,9 @@ 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." }, + { "architecture", frapy_arch, METH_NOARGS, + "architecture () -> gdb.Architecture.\n\ +Return the architecture 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." }, @@ -663,9 +683,8 @@ Return the value of the variable in this frame." }, {NULL} /* Sentinel */ }; -static PyTypeObject frame_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /* ob_size */ +PyTypeObject frame_object_type = { + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Frame", /* tp_name */ sizeof (frame_object), /* tp_basicsize */ 0, /* tp_itemsize */ diff --git a/contrib/gdb-7/gdb/python/py-function.c b/contrib/gdb-7/gdb/python/py-function.c index 59ff65cd9b..bd25263da8 100644 --- a/contrib/gdb-7/gdb/python/py-function.c +++ b/contrib/gdb-7/gdb/python/py-function.c @@ -1,6 +1,6 @@ /* Convenience functions implemented in Python. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -208,8 +208,7 @@ gdbpy_initialize_functions (void) static PyTypeObject fnpy_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Function", /*tp_name*/ sizeof (PyObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-gdb-readline.c b/contrib/gdb-7/gdb/python/py-gdb-readline.c new file mode 100644 index 0000000000..ca7e4a6086 --- /dev/null +++ b/contrib/gdb-7/gdb/python/py-gdb-readline.c @@ -0,0 +1,113 @@ +/* Readline support for Python. + + Copyright (C) 2012-2013 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 "exceptions.h" +#include "top.h" +#include "cli/cli-utils.h" +#include "gdb_string.h" + +#include + +/* Readline function suitable for PyOS_ReadlineFunctionPointer, which + is used for Python's interactive parser and raw_input. In both + cases, sys_stdin and sys_stdout are always stdin and stdout + respectively, as far as I can tell; they are ignored and + command_line_input is used instead. */ + +static char * +gdbpy_readline_wrapper (FILE *sys_stdin, FILE *sys_stdout, + char *prompt) +{ + int n; + char *p = NULL, *q; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + p = command_line_input (prompt, 0, "python"); + + /* Detect user interrupt (Ctrl-C). */ + if (except.reason == RETURN_QUIT) + return NULL; + + /* Handle errors by raising Python exceptions. */ + if (except.reason < 0) + { + /* The thread state is nulled during gdbpy_readline_wrapper, + with the original value saved in the following undocumented + variable (see Python's Parser/myreadline.c and + Modules/readline.c). */ + PyEval_RestoreThread (_PyOS_ReadlineTState); + gdbpy_convert_exception (except); + PyEval_SaveThread (); + return NULL; + } + + /* Detect EOF (Ctrl-D). */ + if (p == NULL) + { + q = PyMem_Malloc (1); + if (q != NULL) + q[0] = '\0'; + return q; + } + + n = strlen (p); + + /* Copy the line to Python and return. */ + q = PyMem_Malloc (n + 2); + if (q != NULL) + { + strncpy (q, p, n); + q[n] = '\n'; + q[n + 1] = '\0'; + } + return q; +} + +/* Initialize Python readline support. */ + +void +gdbpy_initialize_gdb_readline (void) +{ + /* Python's readline module conflicts with GDB's use of readline + since readline is not reentrant. Ideally, a reentrant wrapper to + GDB's readline should be implemented to replace Python's readline + and prevent conflicts. For now, this file implements a + sys.meta_path finder that simply fails to import the readline + module. */ + PyRun_SimpleString ("\ +import sys\n\ +\n\ +class GdbRemoveReadlineFinder:\n\ + def find_module(self, fullname, path=None):\n\ + if fullname == 'readline' and path is None:\n\ + return self\n\ + return None\n\ +\n\ + def load_module(self, fullname):\n\ + raise ImportError('readline module disabled under GDB')\n\ +\n\ +sys.meta_path.append(GdbRemoveReadlineFinder())\n\ +"); + + PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper; +} + diff --git a/contrib/gdb-7/gdb/python/py-inferior.c b/contrib/gdb-7/gdb/python/py-inferior.c index 339a221035..9c84904ad9 100644 --- a/contrib/gdb-7/gdb/python/py-inferior.c +++ b/contrib/gdb-7/gdb/python/py-inferior.c @@ -1,6 +1,6 @@ /* Python interface to inferiors. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -81,7 +81,7 @@ static void python_on_normal_stop (struct bpstats *bs, int print_frame) { struct cleanup *cleanup; - enum target_signal stop_signal; + enum gdb_signal stop_signal; if (!find_thread_ptid (inferior_ptid)) return; @@ -101,7 +101,7 @@ python_on_resume (ptid_t ptid) { struct cleanup *cleanup; - cleanup = ensure_python_env (target_gdbarch, current_language); + cleanup = ensure_python_env (target_gdbarch (), current_language); if (emit_continue_event (ptid) < 0) gdbpy_print_stack (); @@ -115,7 +115,7 @@ python_inferior_exit (struct inferior *inf) struct cleanup *cleanup; const LONGEST *exit_code = NULL; - cleanup = ensure_python_env (target_gdbarch, current_language); + cleanup = ensure_python_env (target_gdbarch (), current_language); if (inf->has_exit_code) exit_code = &inf->exit_code; @@ -180,7 +180,6 @@ inferior_to_inferior_object (struct inferior *inferior) PyObject * find_inferior_object (int pid) { - struct inflist_entry *p; struct inferior *inf = find_inferior_pid (pid); if (inf) @@ -257,7 +256,6 @@ delete_thread_object (struct thread_info *tp, int ignore) { struct cleanup *cleanup; inferior_object *inf_obj; - thread_object *thread_obj; struct threadlist_entry **entry, *tmp; cleanup = ensure_python_env (python_gdbarch, python_language); @@ -302,9 +300,14 @@ infpy_threads (PyObject *self, PyObject *args) struct threadlist_entry *entry; inferior_object *inf_obj = (inferior_object *) self; PyObject *tuple; + volatile struct gdb_exception except; INFPY_REQUIRE_VALID (inf_obj); + TRY_CATCH (except, RETURN_MASK_ALL) + update_thread_list (); + GDB_PY_HANDLE_EXCEPTION (except); + tuple = PyTuple_New (inf_obj->nthreads); if (!tuple) return NULL; @@ -394,7 +397,7 @@ gdbpy_inferiors (PyObject *unused, PyObject *unused2) /* Membuf and memory manipulation. */ -/* Implementation of gdb.read_memory (address, length). +/* Implementation of Inferior.read_memory (address, length). Returns a Python buffer object with LENGTH bytes of the inferior's memory at ADDRESS. Both arguments are integers. Returns NULL on error, with a python exception set. */ @@ -405,8 +408,7 @@ infpy_read_memory (PyObject *self, PyObject *args, PyObject *kw) CORE_ADDR addr, length; void *buffer = NULL; membuf_object *membuf_obj; - PyObject *addr_obj, *length_obj; - struct cleanup *cleanups; + PyObject *addr_obj, *length_obj, *result; volatile struct gdb_exception except; static char *keywords[] = { "address", "length", NULL }; @@ -414,8 +416,6 @@ infpy_read_memory (PyObject *self, PyObject *args, PyObject *kw) &addr_obj, &length_obj)) return NULL; - cleanups = make_cleanup (null_cleanup, NULL); - TRY_CATCH (except, RETURN_MASK_ALL) { if (!get_addr_from_python (addr_obj, &addr) @@ -426,42 +426,46 @@ infpy_read_memory (PyObject *self, PyObject *args, PyObject *kw) } buffer = xmalloc (length); - make_cleanup (xfree, buffer); read_memory (addr, buffer, length); } if (except.reason < 0) { - do_cleanups (cleanups); + xfree (buffer); GDB_PY_HANDLE_EXCEPTION (except); } if (error) { - do_cleanups (cleanups); + xfree (buffer); return NULL; } 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.")); - do_cleanups (cleanups); return NULL; } - discard_cleanups (cleanups); - membuf_obj->buffer = buffer; membuf_obj->addr = addr; membuf_obj->length = length; - return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0, - Py_END_OF_BUFFER); +#ifdef IS_PY3K + result = PyMemoryView_FromObject ((PyObject *) membuf_obj); +#else + result = PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0, + Py_END_OF_BUFFER); +#endif + Py_DECREF (membuf_obj); + + return result; } -/* Implementation of gdb.write_memory (address, buffer [, length]). +/* Implementation of Inferior.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 @@ -477,12 +481,22 @@ infpy_write_memory (PyObject *self, PyObject *args, PyObject *kw) PyObject *addr_obj, *length_obj = NULL; volatile struct gdb_exception except; static char *keywords[] = { "address", "buffer", "length", NULL }; +#ifdef IS_PY3K + Py_buffer pybuf; + if (! PyArg_ParseTupleAndKeywords (args, kw, "Os*|O", keywords, + &addr_obj, &pybuf, + &length_obj)) + return NULL; + buffer = pybuf.buf; + buf_len = pybuf.len; +#else if (! PyArg_ParseTupleAndKeywords (args, kw, "Os#|O", keywords, &addr_obj, &buffer, &buf_len, &length_obj)) return NULL; +#endif TRY_CATCH (except, RETURN_MASK_ALL) { @@ -499,10 +513,14 @@ infpy_write_memory (PyObject *self, PyObject *args, PyObject *kw) error = 1; break; } - write_memory (addr, buffer, length); + write_memory_with_notification (addr, buffer, length); } +#ifdef IS_PY3K + PyBuffer_Release (&pybuf); +#endif GDB_PY_HANDLE_EXCEPTION (except); + if (error) return NULL; @@ -514,7 +532,7 @@ static void mbpy_dealloc (PyObject *self) { xfree (((membuf_object *) self)->buffer); - self->ob_type->tp_free (self); + Py_TYPE (self)->tp_free (self); } /* Return a description of the Membuf object. */ @@ -529,6 +547,24 @@ which is %s bytes long."), pulongest (membuf_obj->length)); } +#ifdef IS_PY3K + +static int +get_buffer (PyObject *self, Py_buffer *buf, int flags) +{ + membuf_object *membuf_obj = (membuf_object *) self; + int ret; + + ret = PyBuffer_FillInfo (buf, self, membuf_obj->buffer, + membuf_obj->length, 0, + PyBUF_CONTIG); + buf->format = "c"; + + return ret; +} + +#else + static Py_ssize_t get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) { @@ -573,6 +609,8 @@ get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr) return ret; } +#endif /* IS_PY3K */ + /* Implementation of gdb.search_memory (address, length, pattern). ADDRESS is the address to start the search. LENGTH specifies the scope of the @@ -586,17 +624,41 @@ infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw) { CORE_ADDR start_addr, length; static char *keywords[] = { "address", "length", "pattern", NULL }; - PyObject *pattern, *start_addr_obj, *length_obj; + PyObject *start_addr_obj, *length_obj; volatile struct gdb_exception except; Py_ssize_t pattern_size; const void *buffer; CORE_ADDR found_addr; int found = 0; +#ifdef IS_PY3K + Py_buffer pybuf; - if (! PyArg_ParseTupleAndKeywords (args, kw, "OOO", keywords, + if (! PyArg_ParseTupleAndKeywords (args, kw, "OOs*", keywords, &start_addr_obj, &length_obj, + &pybuf)) + return NULL; + + buffer = pybuf.buf; + pattern_size = pybuf.len; +#else + PyObject *pattern; + + if (! PyArg_ParseTupleAndKeywords (args, kw, "OOO", keywords, + &start_addr_obj, &length_obj, &pattern)) + return NULL; + + if (!PyObject_CheckReadBuffer (pattern)) + { + PyErr_SetString (PyExc_RuntimeError, + _("The pattern is not a Python buffer.")); + + return NULL; + } + + if (PyObject_AsReadBuffer (pattern, &buffer, &pattern_size) == -1) return NULL; +#endif if (get_addr_from_python (start_addr_obj, &start_addr) && get_addr_from_python (length_obj, &length)) @@ -605,6 +667,10 @@ infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw) { PyErr_SetString (PyExc_ValueError, _("Search range is empty.")); + +#ifdef IS_PY3K + PyBuffer_Release (&pybuf); +#endif return NULL; } /* Watch for overflows. */ @@ -614,23 +680,15 @@ infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw) PyErr_SetString (PyExc_ValueError, _("The search range is too large.")); +#ifdef IS_PY3K + PyBuffer_Release (&pybuf); +#endif return NULL; } } else return NULL; - if (!PyObject_CheckReadBuffer (pattern)) - { - PyErr_SetString (PyExc_RuntimeError, - _("The pattern is not a Python buffer.")); - - return NULL; - } - - if (PyObject_AsReadBuffer (pattern, &buffer, &pattern_size) == -1) - return NULL; - TRY_CATCH (except, RETURN_MASK_ALL) { found = target_search_memory (start_addr, length, @@ -639,6 +697,10 @@ infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw) } GDB_PY_HANDLE_EXCEPTION (except); +#ifdef IS_PY3K + PyBuffer_Release (&pybuf); +#endif + if (found) return PyLong_FromLong (found_addr); else @@ -726,7 +788,7 @@ gdbpy_initialize_inferior (void) (PyObject *) &inferior_object_type); infpy_inf_data_key = - register_inferior_data_with_cleanup (py_free_inferior); + register_inferior_data_with_cleanup (NULL, py_free_inferior); observer_attach_new_thread (add_thread_object); observer_attach_thread_exit (delete_thread_object); @@ -778,8 +840,7 @@ Return a long with the address of a match, or None." }, static PyTypeObject inferior_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /* ob_size */ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Inferior", /* tp_name */ sizeof (inferior_object), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -818,6 +879,15 @@ static PyTypeObject inferior_object_type = 0 /* tp_alloc */ }; +#ifdef IS_PY3K + +static PyBufferProcs buffer_procs = +{ + get_buffer +}; + +#else + /* Python doesn't provide a decent way to get compatibility here. */ #if HAVE_LIBPYTHON2_4 #define CHARBUFFERPROC_NAME getcharbufferproc @@ -833,10 +903,10 @@ static PyBufferProcs buffer_procs = { Python 2.5. */ (CHARBUFFERPROC_NAME) get_char_buffer }; +#endif /* IS_PY3K */ static PyTypeObject membuf_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Membuf", /*tp_name*/ sizeof (membuf_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-infthread.c b/contrib/gdb-7/gdb/python/py-infthread.c index 3a37ef787e..a5a083f218 100644 --- a/contrib/gdb-7/gdb/python/py-infthread.c +++ b/contrib/gdb-7/gdb/python/py-infthread.c @@ -1,6 +1,6 @@ /* Python interface to inferior threads. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -59,7 +59,7 @@ static void thpy_dealloc (PyObject *self) { Py_DECREF (((thread_object *) self)->inf_obj); - self->ob_type->tp_free (self); + Py_TYPE (self)->tp_free (self); } static PyObject * @@ -162,7 +162,6 @@ static PyObject * thpy_switch (PyObject *self, PyObject *args) { thread_object *thread_obj = (thread_object *) self; - struct cleanup *cleanup; volatile struct gdb_exception except; THPY_REQUIRE_VALID (thread_obj); @@ -302,8 +301,7 @@ Return whether the thread is exited." }, static PyTypeObject thread_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.InferiorThread", /*tp_name*/ sizeof (thread_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-lazy-string.c b/contrib/gdb-7/gdb/python/py-lazy-string.c index 11048b3e50..68350679b8 100644 --- a/contrib/gdb-7/gdb/python/py-lazy-string.c +++ b/contrib/gdb-7/gdb/python/py-lazy-string.c @@ -1,6 +1,6 @@ /* Python interface to lazy strings. - Copyright (C) 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -84,7 +84,7 @@ stpy_get_length (PyObject *self, void *closure) return PyLong_FromLong (self_string->length); } -PyObject * +static PyObject * stpy_get_type (PyObject *self, void *closure) { lazy_string_object *str_obj = (lazy_string_object *) self; @@ -216,8 +216,7 @@ static PyGetSetDef lazy_string_object_getset[] = { }; static PyTypeObject lazy_string_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.LazyString", /*tp_name*/ sizeof (lazy_string_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-newobjfileevent.c b/contrib/gdb-7/gdb/python/py-newobjfileevent.c index 1e26b044b4..538e2d8e2f 100644 --- a/contrib/gdb-7/gdb/python/py-newobjfileevent.c +++ b/contrib/gdb-7/gdb/python/py-newobjfileevent.c @@ -1,6 +1,6 @@ /* Python interface to new object file loading events. - Copyright (C) 2011-2012 Free Software Foundation, Inc. + Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,11 +17,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-event.h" static PyTypeObject new_objfile_event_object_type; -PyObject * +static PyObject * create_new_objfile_event_object (struct objfile *objfile) { PyObject *objfile_event; @@ -31,6 +32,8 @@ create_new_objfile_event_object (struct objfile *objfile) if (!objfile_event) goto fail; + /* Note that objfile_to_objfile_object returns a borrowed reference, + so we don't need a decref here. */ py_objfile = objfile_to_objfile_object (objfile); if (!py_objfile || evpy_add_attribute (objfile_event, "new_objfile", diff --git a/contrib/gdb-7/gdb/python/py-objfile.c b/contrib/gdb-7/gdb/python/py-objfile.c index 9fa6813f62..db51f508b5 100644 --- a/contrib/gdb-7/gdb/python/py-objfile.c +++ b/contrib/gdb-7/gdb/python/py-objfile.c @@ -1,6 +1,6 @@ /* Python interface to objfiles. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -32,6 +32,9 @@ typedef struct /* The pretty-printer list of functions. */ PyObject *printers; + + /* The type-printer list. */ + PyObject *type_printers; } objfile_object; static PyTypeObject objfile_object_type; @@ -58,7 +61,8 @@ objfpy_dealloc (PyObject *o) objfile_object *self = (objfile_object *) o; Py_XDECREF (self->printers); - self->ob_type->tp_free ((PyObject *) self); + Py_XDECREF (self->type_printers); + Py_TYPE (self)->tp_free (self); } static PyObject * @@ -76,6 +80,13 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords) Py_DECREF (self); return NULL; } + + self->type_printers = PyList_New (0); + if (!self->type_printers) + { + Py_DECREF (self); + return NULL; + } } return (PyObject *) self; } @@ -118,6 +129,48 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) return 0; } +/* Get the 'type_printers' attribute. */ + +static PyObject * +objfpy_get_type_printers (PyObject *o, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + + Py_INCREF (self->type_printers); + return self->type_printers; +} + +/* Set the 'type_printers' attribute. */ + +static int +objfpy_set_type_printers (PyObject *o, PyObject *value, void *ignore) +{ + PyObject *tmp; + objfile_object *self = (objfile_object *) o; + + if (! value) + { + PyErr_SetString (PyExc_TypeError, + _("Cannot delete the type_printers attribute.")); + return -1; + } + + if (! PyList_Check (value)) + { + PyErr_SetString (PyExc_TypeError, + _("The type_printers attribute must be a list.")); + return -1; + } + + /* Take care in case the LHS and RHS are related somehow. */ + tmp = self->type_printers; + Py_INCREF (value); + self->type_printers = value; + Py_XDECREF (tmp); + + return 0; +} + /* Implementation of gdb.Objfile.is_valid (self) -> Boolean. Returns True if this object file still exists in GDB. */ @@ -172,6 +225,13 @@ objfile_to_objfile_object (struct objfile *objfile) return NULL; } + object->type_printers = PyList_New (0); + if (!object->type_printers) + { + Py_DECREF (object); + return NULL; + } + set_objfile_data (objfile, objfpy_objfile_data_key, object); } } @@ -210,13 +270,14 @@ static PyGetSetDef objfile_getset[] = "The objfile's filename, or None.", NULL }, { "pretty_printers", objfpy_get_printers, objfpy_set_printers, "Pretty printers.", NULL }, + { "type_printers", objfpy_get_type_printers, objfpy_set_type_printers, + "Type printers.", NULL }, { NULL } }; static PyTypeObject objfile_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Objfile", /*tp_name*/ sizeof (objfile_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-param.c b/contrib/gdb-7/gdb/python/py-param.c index 963427e57d..1970714d09 100644 --- a/contrib/gdb-7/gdb/python/py-param.c +++ b/contrib/gdb-7/gdb/python/py-param.c @@ -1,6 +1,6 @@ /* GDB parameters implemented in Python - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -102,7 +102,11 @@ static PyObject * get_attr (PyObject *obj, PyObject *attr_name) { if (PyString_Check (attr_name) +#ifdef IS_PY3K + && ! PyUnicode_CompareWithASCIIString (attr_name, "value")) +#else && ! strcmp (PyString_AsString (attr_name), "value")) +#endif { parmpy_object *self = (parmpy_object *) obj; @@ -276,7 +280,11 @@ static int set_attr (PyObject *obj, PyObject *attr_name, PyObject *val) { if (PyString_Check (attr_name) +#ifdef IS_PY3K + && ! PyUnicode_CompareWithASCIIString (attr_name, "value")) +#else && ! strcmp (PyString_AsString (attr_name), "value")) +#endif { if (!val) { @@ -773,8 +781,7 @@ gdbpy_initialize_parameters (void) static PyTypeObject parmpy_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Parameter", /*tp_name*/ sizeof (parmpy_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-prettyprint.c b/contrib/gdb-7/gdb/python/py-prettyprint.c index 86d4f2ce6e..dbf6c22a5f 100644 --- a/contrib/gdb-7/gdb/python/py-prettyprint.c +++ b/contrib/gdb-7/gdb/python/py-prettyprint.c @@ -1,6 +1,6 @@ /* Python pretty-printing - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -162,9 +162,10 @@ find_pretty_printer_from_gdb (PyObject *value) PyObject *function; /* Fetch the global pretty printer list. */ - if (! PyObject_HasAttrString (gdb_module, "pretty_printers")) + if (gdb_python_module == NULL + || ! PyObject_HasAttrString (gdb_python_module, "pretty_printers")) Py_RETURN_NONE; - pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers"); + pp_list = PyObject_GetAttrString (gdb_python_module, "pretty_printers"); if (pp_list == NULL || ! PyList_Check (pp_list)) { Py_XDECREF (pp_list); @@ -347,8 +348,13 @@ print_string_repr (PyObject *printer, const char *hint, struct type *type; make_cleanup_py_decref (string); +#ifdef IS_PY3K + output = (gdb_byte *) PyBytes_AS_STRING (string); + length = PyBytes_GET_SIZE (string); +#else output = PyString_AsString (string); length = PyString_Size (string); +#endif type = builtin_type (gdbarch)->builtin_char; if (hint && !strcmp (hint, "string")) @@ -382,6 +388,7 @@ print_string_repr (PyObject *printer, const char *hint, return result; } +#ifndef IS_PY3K static void py_restore_tstate (void *p) { @@ -457,6 +464,7 @@ push_dummy_python_frame (void) make_cleanup (py_restore_tstate, frame->f_back); return (PyObject *) frame; } +#endif /* Helper for apply_val_pretty_printer that formats children of the printer, if any exist. If is_py_none is true, then nothing has @@ -470,7 +478,10 @@ print_children (PyObject *printer, const char *hint, { int is_map, is_array, done_flag, pretty; unsigned int i; - PyObject *children, *iter, *frame; + PyObject *children, *iter; +#ifndef IS_PY3K + PyObject *frame; +#endif struct cleanup *cleanups; if (! PyObject_HasAttr (printer, gdbpy_children_cst)) @@ -514,6 +525,7 @@ print_children (PyObject *printer, const char *hint, /* 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. */ +#ifndef IS_PY3K frame = push_dummy_python_frame (); if (!frame) { @@ -521,6 +533,7 @@ print_children (PyObject *printer, const char *hint, goto done; } make_cleanup_py_decref (frame); +#endif done_flag = 0; for (i = 0; i < options->print_max; ++i) diff --git a/contrib/gdb-7/gdb/python/py-progspace.c b/contrib/gdb-7/gdb/python/py-progspace.c index 1cb82408ce..45a5193b0a 100644 --- a/contrib/gdb-7/gdb/python/py-progspace.c +++ b/contrib/gdb-7/gdb/python/py-progspace.c @@ -1,6 +1,6 @@ /* Python interface to program spaces. - Copyright (C) 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -34,6 +34,9 @@ typedef struct /* The pretty-printer list of functions. */ PyObject *printers; + + /* The type-printer list. */ + PyObject *type_printers; } pspace_object; static PyTypeObject pspace_object_type; @@ -66,7 +69,8 @@ pspy_dealloc (PyObject *self) pspace_object *ps_self = (pspace_object *) self; Py_XDECREF (ps_self->printers); - self->ob_type->tp_free (self); + Py_XDECREF (ps_self->type_printers); + Py_TYPE (self)->tp_free (self); } static PyObject * @@ -84,6 +88,13 @@ pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords) Py_DECREF (self); return NULL; } + + self->type_printers = PyList_New (0); + if (!self->type_printers) + { + Py_DECREF (self); + return NULL; + } } return (PyObject *) self; } @@ -126,6 +137,48 @@ pspy_set_printers (PyObject *o, PyObject *value, void *ignore) return 0; } +/* Get the 'type_printers' attribute. */ + +static PyObject * +pspy_get_type_printers (PyObject *o, void *ignore) +{ + pspace_object *self = (pspace_object *) o; + + Py_INCREF (self->type_printers); + return self->type_printers; +} + +/* Set the 'type_printers' attribute. */ + +static int +pspy_set_type_printers (PyObject *o, PyObject *value, void *ignore) +{ + PyObject *tmp; + pspace_object *self = (pspace_object *) o; + + if (! value) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete the type_printers attribute"); + return -1; + } + + if (! PyList_Check (value)) + { + PyErr_SetString (PyExc_TypeError, + "the type_printers attribute must be a list"); + return -1; + } + + /* Take care in case the LHS and RHS are related somehow. */ + tmp = self->type_printers; + Py_INCREF (value); + self->type_printers = value; + Py_XDECREF (tmp); + + return 0; +} + /* Clear the PSPACE pointer in a Pspace object and remove the reference. */ @@ -168,6 +221,13 @@ pspace_to_pspace_object (struct program_space *pspace) return NULL; } + object->type_printers = PyList_New (0); + if (!object->type_printers) + { + Py_DECREF (object); + return NULL; + } + set_program_space_data (pspace, pspy_pspace_data_key, object); } } @@ -179,7 +239,7 @@ void gdbpy_initialize_pspace (void) { pspy_pspace_data_key - = register_program_space_data_with_cleanup (py_free_pspace); + = register_program_space_data_with_cleanup (NULL, py_free_pspace); if (PyType_Ready (&pspace_object_type) < 0) return; @@ -197,13 +257,14 @@ static PyGetSetDef pspace_getset[] = "The progspace's main filename, or None.", NULL }, { "pretty_printers", pspy_get_printers, pspy_set_printers, "Pretty printers.", NULL }, + { "type_printers", pspy_get_type_printers, pspy_set_type_printers, + "Type printers.", NULL }, { NULL } }; static PyTypeObject pspace_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Progspace", /*tp_name*/ sizeof (pspace_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-signalevent.c b/contrib/gdb-7/gdb/python/py-signalevent.c index 323d6f6706..3d64936769 100644 --- a/contrib/gdb-7/gdb/python/py-signalevent.c +++ b/contrib/gdb-7/gdb/python/py-signalevent.c @@ -1,6 +1,6 @@ /* Python interface to inferior signal stop events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,32 +17,39 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-stopevent.h" static PyTypeObject signal_event_object_type; PyObject * -create_signal_event_object (enum target_signal stop_signal) +create_signal_event_object (enum gdb_signal stop_signal) { const char *signal_name; + PyObject *signal_name_obj = NULL; PyObject *signal_event_obj = create_stop_event_object (&signal_event_object_type); if (!signal_event_obj) goto fail; - signal_name = target_signal_to_name (stop_signal); + signal_name = gdb_signal_to_name (stop_signal); + signal_name_obj = PyString_FromString (signal_name); + if (signal_name_obj == NULL) + goto fail; if (evpy_add_attribute (signal_event_obj, "stop_signal", - PyString_FromString (signal_name)) < 0) + signal_name_obj) < 0) goto fail; + Py_DECREF (signal_name_obj); return signal_event_obj; - fail: - Py_XDECREF (signal_event_obj); - return NULL; + fail: + Py_XDECREF (signal_name_obj); + Py_XDECREF (signal_event_obj); + return NULL; } GDBPY_NEW_EVENT_TYPE (signal, diff --git a/contrib/gdb-7/gdb/python/py-stopevent.c b/contrib/gdb-7/gdb/python/py-stopevent.c index 1df4ae9e1d..8e03c04354 100644 --- a/contrib/gdb-7/gdb/python/py-stopevent.c +++ b/contrib/gdb-7/gdb/python/py-stopevent.c @@ -1,6 +1,6 @@ /* Python interface to inferior stop events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-stopevent.h" PyObject * @@ -42,7 +43,7 @@ create_stop_event_object (PyTypeObject *py_type) returns -1. */ int -emit_stop_event (struct bpstats *bs, enum target_signal stop_signal) +emit_stop_event (struct bpstats *bs, enum gdb_signal stop_signal) { PyObject *stop_event_obj = NULL; /* Appease GCC warning. */ PyObject *list = NULL; @@ -81,11 +82,12 @@ emit_stop_event (struct bpstats *bs, enum target_signal stop_signal) stop_event_obj = create_breakpoint_event_object (list, first_bp); if (!stop_event_obj) goto fail; + Py_DECREF (list); } /* Check if the signal is "Signal 0" or "Trace/breakpoint trap". */ - if (stop_signal != TARGET_SIGNAL_0 - && stop_signal != TARGET_SIGNAL_TRAP) + if (stop_signal != GDB_SIGNAL_0 + && stop_signal != GDB_SIGNAL_TRAP) { stop_event_obj = create_signal_event_object (stop_signal); diff --git a/contrib/gdb-7/gdb/python/py-stopevent.h b/contrib/gdb-7/gdb/python/py-stopevent.h index df642860c7..5da6462229 100644 --- a/contrib/gdb-7/gdb/python/py-stopevent.h +++ b/contrib/gdb-7/gdb/python/py-stopevent.h @@ -1,6 +1,6 @@ /* Python interface to inferior events. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -26,11 +26,11 @@ extern PyObject *create_stop_event_object (PyTypeObject *py_type); extern void stop_evpy_dealloc (PyObject *self); extern int emit_stop_event (struct bpstats *bs, - enum target_signal stop_signal); + enum gdb_signal stop_signal); extern PyObject *create_breakpoint_event_object (PyObject *breakpoint_list, PyObject *first_bp); -extern PyObject *create_signal_event_object (enum target_signal stop_signal); +extern PyObject *create_signal_event_object (enum gdb_signal stop_signal); #endif /* GDB_PY_STOPEVENT_H */ diff --git a/contrib/gdb-7/gdb/python/py-symbol.c b/contrib/gdb-7/gdb/python/py-symbol.c index 9d32a71773..def0fdd984 100644 --- a/contrib/gdb-7/gdb/python/py-symbol.c +++ b/contrib/gdb-7/gdb/python/py-symbol.c @@ -1,6 +1,6 @@ /* Python interface to symbols. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -183,6 +183,42 @@ sympy_is_variable (PyObject *self, void *closure) || class == LOC_OPTIMIZED_OUT)); } +/* Implementation of gdb.Symbol.needs_frame -> Boolean. + Returns true iff the symbol needs a frame for evaluation. */ + +static PyObject * +sympy_needs_frame (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + volatile struct gdb_exception except; + int result = 0; + + SYMPY_REQUIRE_VALID (self, symbol); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + result = symbol_read_needs_frame (symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (result) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Implementation of gdb.Symbol.line -> int. + Returns the line number at which the symbol was defined. */ + +static PyObject * +sympy_line (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + + SYMPY_REQUIRE_VALID (self, symbol); + + return PyInt_FromLong (SYMBOL_LINE (symbol)); +} + /* Implementation of gdb.Symbol.is_valid (self) -> Boolean. Returns True if this Symbol still exists in GDB. */ @@ -198,6 +234,53 @@ sympy_is_valid (PyObject *self, PyObject *args) Py_RETURN_TRUE; } +/* Implementation of gdb.Symbol.value (self[, frame]) -> gdb.Value. Returns + the value of the symbol, or an error in various circumstances. */ + +static PyObject * +sympy_value (PyObject *self, PyObject *args) +{ + struct symbol *symbol = NULL; + struct frame_info *frame_info = NULL; + PyObject *frame_obj = NULL; + struct value *value = NULL; + volatile struct gdb_exception except; + + if (!PyArg_ParseTuple (args, "|O", &frame_obj)) + return NULL; + + if (frame_obj != NULL && !PyObject_TypeCheck (frame_obj, &frame_object_type)) + { + PyErr_SetString (PyExc_TypeError, "argument is not a frame"); + return NULL; + } + + SYMPY_REQUIRE_VALID (self, symbol); + if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF) + { + PyErr_SetString (PyExc_TypeError, "cannot get the value of a typedef"); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (frame_obj != NULL) + { + frame_info = frame_object_to_frame_info (frame_obj); + if (frame_info == NULL) + error (_("invalid frame")); + } + + if (symbol_read_needs_frame (symbol) && frame_info == NULL) + error (_("symbol requires a frame to compute its value")); + + value = read_var_value (symbol, frame_info); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (value); +} + /* Given a symbol, and a symbol_object that has previously been allocated and initialized, populate the symbol_object with the struct symbol data. Also, register the symbol_object life-cycle @@ -252,7 +335,7 @@ sympy_dealloc (PyObject *obj) if (sym_obj->prev) sym_obj->prev->next = sym_obj->next; - else if (SYMBOL_SYMTAB (sym_obj->symbol)) + else if (sym_obj->symbol && SYMBOL_SYMTAB (sym_obj->symbol)) { set_objfile_data (SYMBOL_SYMTAB (sym_obj->symbol)->objfile, sympy_objfile_data_key, sym_obj->next); @@ -271,7 +354,8 @@ sympy_dealloc (PyObject *obj) PyObject * gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw) { - int domain = VAR_DOMAIN, is_a_field_of_this = 0; + int domain = VAR_DOMAIN; + struct field_of_this_result is_a_field_of_this; const char *name; static char *keywords[] = { "name", "block", "domain", NULL }; struct symbol *symbol = NULL; @@ -324,7 +408,7 @@ gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw) } PyTuple_SET_ITEM (ret_tuple, 0, sym_obj); - bool_obj = is_a_field_of_this? Py_True : Py_False; + bool_obj = (is_a_field_of_this.type != NULL) ? Py_True : Py_False; Py_INCREF (bool_obj); PyTuple_SET_ITEM (ret_tuple, 1, bool_obj); @@ -460,6 +544,10 @@ to display demangled or mangled names.", NULL }, "True if the symbol is a function or method." }, { "is_variable", sympy_is_variable, NULL, "True if the symbol is a variable." }, + { "needs_frame", sympy_needs_frame, NULL, + "True if the symbol requires a frame for evaluation." }, + { "line", sympy_line, NULL, + "The source line number at which the symbol was defined." }, { NULL } /* Sentinel */ }; @@ -467,12 +555,14 @@ static PyMethodDef symbol_object_methods[] = { { "is_valid", sympy_is_valid, METH_NOARGS, "is_valid () -> Boolean.\n\ Return true if this symbol is valid, false if not." }, + { "value", sympy_value, METH_VARARGS, + "value ([frame]) -> gdb.Value\n\ +Return the value of the symbol." }, {NULL} /* Sentinel */ }; PyTypeObject symbol_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Symbol", /*tp_name*/ sizeof (symbol_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-symtab.c b/contrib/gdb-7/gdb/python/py-symtab.c index 09b760fc4d..6fa8ecb8f0 100644 --- a/contrib/gdb-7/gdb/python/py-symtab.c +++ b/contrib/gdb-7/gdb/python/py-symtab.c @@ -1,6 +1,6 @@ /* Python interface to symbol tables. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -23,6 +23,7 @@ #include "source.h" #include "python-internal.h" #include "objfiles.h" +#include "block.h" typedef struct stpy_symtab_object { PyObject_HEAD @@ -90,7 +91,7 @@ stpy_str (PyObject *self) STPY_REQUIRE_VALID (self, symtab); - result = PyString_FromString (symtab->filename); + result = PyString_FromString (symtab_to_filename_for_display (symtab)); return result; } @@ -100,11 +101,12 @@ stpy_get_filename (PyObject *self, void *closure) { PyObject *str_obj; struct symtab *symtab = NULL; + const char *filename; STPY_REQUIRE_VALID (self, symtab); + filename = symtab_to_filename_for_display (symtab); - str_obj = PyString_Decode (symtab->filename, - strlen (symtab->filename), + str_obj = PyString_Decode (filename, strlen (filename), host_charset (), NULL); return str_obj; } @@ -125,17 +127,14 @@ stpy_get_objfile (PyObject *self, void *closure) static PyObject * stpy_fullname (PyObject *self, PyObject *args) { - char *fullname; + const char *fullname; struct symtab *symtab = NULL; STPY_REQUIRE_VALID (self, symtab); fullname = symtab_to_fullname (symtab); - if (fullname) - return PyString_Decode (fullname, strlen (fullname), - host_charset (), NULL); - Py_RETURN_NONE; + return PyString_Decode (fullname, strlen (fullname), host_charset (), NULL); } /* Implementation of gdb.Symtab.is_valid (self) -> Boolean. @@ -153,10 +152,43 @@ stpy_is_valid (PyObject *self, PyObject *args) Py_RETURN_TRUE; } +/* Return the GLOBAL_BLOCK of the underlying symtab. */ + +static PyObject * +stpy_global_block (PyObject *self, PyObject *args) +{ + struct symtab *symtab = NULL; + struct block *block = NULL; + struct blockvector *blockvector; + + STPY_REQUIRE_VALID (self, symtab); + + blockvector = BLOCKVECTOR (symtab); + block = BLOCKVECTOR_BLOCK (blockvector, GLOBAL_BLOCK); + return block_to_block_object (block, symtab->objfile); +} + +/* Return the STATIC_BLOCK of the underlying symtab. */ + +static PyObject * +stpy_static_block (PyObject *self, PyObject *args) +{ + struct symtab *symtab = NULL; + struct block *block = NULL; + struct blockvector *blockvector; + + STPY_REQUIRE_VALID (self, symtab); + + blockvector = BLOCKVECTOR (symtab); + block = BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK); + return block_to_block_object (block, symtab->objfile); +} + static PyObject * salpy_str (PyObject *self) { - char *s, *filename; + char *s; + const char *filename; sal_object *sal_obj; PyObject *result; struct symtab_and_line *sal = NULL; @@ -165,7 +197,7 @@ salpy_str (PyObject *self) sal_obj = (sal_object *) self; filename = (sal_obj->symtab == (symtab_object *) Py_None) - ? "" : sal_obj->symtab->symtab->filename; + ? "" : symtab_to_filename_for_display (sal_obj->symtab->symtab); s = xstrprintf ("symbol and line for %s, line %d", filename, sal->line); @@ -204,6 +236,22 @@ salpy_get_pc (PyObject *self, void *closure) return gdb_py_long_from_ulongest (sal->pc); } +/* Implementation of the get method for the 'last' attribute of + gdb.Symtab_and_line. */ + +static PyObject * +salpy_get_last (PyObject *self, void *closure) +{ + struct symtab_and_line *sal = NULL; + + SALPY_REQUIRE_VALID (self, sal); + + if (sal->end > 0) + return gdb_py_long_from_ulongest (sal->end - 1); + else + Py_RETURN_NONE; +} + static PyObject * salpy_get_line (PyObject *self, void *closure) { @@ -258,7 +306,7 @@ salpy_dealloc (PyObject *self) Py_DECREF (self_sal->symtab); xfree (self_sal->sal); - self_sal->ob_type->tp_free (self); + Py_TYPE (self)->tp_free (self); } /* Given a sal, and a sal_object that has previously been allocated @@ -421,7 +469,10 @@ del_objfile_sal (struct objfile *objfile, void *datum) { sal_object *next = obj->next; - obj->symtab = NULL; + Py_DECREF (obj->symtab); + obj->symtab = (symtab_object *) Py_None; + Py_INCREF (Py_None); + obj->next = NULL; obj->prev = NULL; xfree (obj->sal); @@ -477,12 +528,17 @@ Return true if this symbol table is valid, false if not." }, { "fullname", stpy_fullname, METH_NOARGS, "fullname () -> String.\n\ Return the symtab's full source filename." }, + { "global_block", stpy_global_block, METH_NOARGS, + "global_block () -> gdb.Block.\n\ +Return the global block of the symbol table." }, + { "static_block", stpy_static_block, METH_NOARGS, + "static_block () -> gdb.Block.\n\ +Return the static block of the symbol table." }, {NULL} /* Sentinel */ }; static PyTypeObject symtab_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Symtab", /*tp_name*/ sizeof (symtab_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ @@ -517,6 +573,8 @@ static PyTypeObject symtab_object_type = { 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 }, + { "last", salpy_get_last, NULL, + "Return the symtab_and_line's last address.", NULL }, { "line", salpy_get_line, NULL, "Return the symtab_and_line's line.", NULL }, {NULL} /* Sentinel */ @@ -530,8 +588,7 @@ Return true if this symbol table and line is valid, false if not." }, }; static PyTypeObject sal_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Symtab_and_line", /*tp_name*/ sizeof (sal_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-threadevent.c b/contrib/gdb-7/gdb/python/py-threadevent.c index 67f9e2006a..7e13f14b4a 100644 --- a/contrib/gdb-7/gdb/python/py-threadevent.c +++ b/contrib/gdb-7/gdb/python/py-threadevent.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2009-2012 Free Software Foundation, Inc. +/* Copyright (C) 2009-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -15,13 +15,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" #include "py-event.h" /* thread events can either be thread specific or process wide. If gdb is running in non-stop mode then the event is thread specific, otherwise it is process wide. This function returns the currently stopped thread in non-stop mode and - Py_None otherwise. */ + Py_None otherwise. In each case it returns a borrowed reference. */ static PyObject * get_event_thread (void) @@ -39,8 +40,6 @@ get_event_thread (void) return NULL; } - Py_INCREF (thread); - return thread; } diff --git a/contrib/gdb-7/gdb/python/py-type.c b/contrib/gdb-7/gdb/python/py-type.c index dadb0375a9..051cff07f1 100644 --- a/contrib/gdb-7/gdb/python/py-type.c +++ b/contrib/gdb-7/gdb/python/py-type.c @@ -1,6 +1,6 @@ /* Python interface to types. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -30,6 +30,7 @@ #include "vec.h" #include "bcache.h" #include "dwarf2loc.h" +#include "typeprint.h" typedef struct pyty_type_object { @@ -85,6 +86,7 @@ static PyObject *typy_make_iter (PyObject *self, enum gdbpy_iter_kind kind); static struct pyty_code pyty_codes[] = { + ENTRY (TYPE_CODE_BITSTRING), ENTRY (TYPE_CODE_PTR), ENTRY (TYPE_CODE_ARRAY), ENTRY (TYPE_CODE_STRUCT), @@ -98,7 +100,6 @@ static struct pyty_code pyty_codes[] = 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), @@ -122,7 +123,7 @@ field_dealloc (PyObject *obj) field_object *f = (field_object *) obj; Py_XDECREF (f->dict); - f->ob_type->tp_free (obj); + Py_TYPE (obj)->tp_free (obj); } static PyObject * @@ -167,12 +168,26 @@ convert_field (struct type *type, int field) if (!field_is_static (&TYPE_FIELD (type, field))) { - arg = PyLong_FromLong (TYPE_FIELD_BITPOS (type, field)); + const char *attrstring; + + if (TYPE_CODE (type) == TYPE_CODE_ENUM) + { + arg = gdb_py_long_from_longest (TYPE_FIELD_ENUMVAL (type, field)); + attrstring = "enumval"; + } + else + { + arg = gdb_py_long_from_longest (TYPE_FIELD_BITPOS (type, field)); + attrstring = "bitpos"; + } + if (!arg) goto fail; - if (PyObject_SetAttrString (result, "bitpos", arg) < 0) + /* At least python-2.4 had the second parameter non-const. */ + if (PyObject_SetAttrString (result, (char *) attrstring, arg) < 0) goto failarg; + Py_DECREF (arg); } if (TYPE_FIELD_NAME (type, field)) @@ -186,11 +201,13 @@ convert_field (struct type *type, int field) goto fail; if (PyObject_SetAttrString (result, "name", arg) < 0) goto failarg; + Py_DECREF (arg); arg = TYPE_FIELD_ARTIFICIAL (type, field) ? Py_True : Py_False; Py_INCREF (arg); if (PyObject_SetAttrString (result, "artificial", arg) < 0) goto failarg; + Py_DECREF (arg); if (TYPE_CODE (type) == TYPE_CODE_CLASS) arg = field < TYPE_N_BASECLASSES (type) ? Py_True : Py_False; @@ -199,12 +216,14 @@ convert_field (struct type *type, int field) Py_INCREF (arg); if (PyObject_SetAttrString (result, "is_base_class", arg) < 0) goto failarg; + Py_DECREF (arg); arg = PyLong_FromLong (TYPE_FIELD_BITSIZE (type, field)); if (!arg) goto fail; if (PyObject_SetAttrString (result, "bitsize", arg) < 0) goto failarg; + Py_DECREF (arg); /* A field can have a NULL type in some situations. */ if (TYPE_FIELD_TYPE (type, field) == NULL) @@ -218,6 +237,7 @@ convert_field (struct type *type, int field) goto fail; if (PyObject_SetAttrString (result, "type", arg) < 0) goto failarg; + Py_DECREF (arg); return result; @@ -403,7 +423,7 @@ typy_strip_typedefs (PyObject *self, PyObject *args) } GDB_PY_HANDLE_EXCEPTION (except); - return type_to_type_object (check_typedef (type)); + return type_to_type_object (type); } /* Strip typedefs and pointers/reference from a type. Then check that @@ -448,10 +468,10 @@ typy_get_composite (struct type *type) return type; } -/* Return an array type. */ +/* Helper for typy_array and typy_vector. */ static PyObject * -typy_array (PyObject *self, PyObject *args) +typy_array_1 (PyObject *self, PyObject *args, int is_vector) { long n1, n2; PyObject *n2_obj = NULL; @@ -490,12 +510,30 @@ typy_array (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { array = lookup_array_range_type (type, n1, n2); + if (is_vector) + make_vector_type (array); } GDB_PY_HANDLE_EXCEPTION (except); return type_to_type_object (array); } +/* Return an array type. */ + +static PyObject * +typy_array (PyObject *self, PyObject *args) +{ + return typy_array_1 (self, args, 0); +} + +/* Return a vector type. */ + +static PyObject * +typy_vector (PyObject *self, PyObject *args) +{ + return typy_array_1 (self, args, 1); +} + /* Return a Type object which represents a pointer to SELF. */ static PyObject * typy_pointer (PyObject *self, PyObject *args) @@ -670,7 +708,7 @@ typy_get_sizeof (PyObject *self, void *closure) } /* Ignore exceptions. */ - return PyLong_FromLong (TYPE_LENGTH (type)); + return gdb_py_long_from_longest (TYPE_LENGTH (type)); } static struct type * @@ -917,7 +955,8 @@ typy_str (PyObject *self) stb = mem_fileopen (); old_chain = make_cleanup_ui_file_delete (stb); - type_print (type_object_to_type (self), "", stb, -1); + LA_PRINT_TYPE (type_object_to_type (self), "", stb, -1, 0, + &type_print_raw_options); thetype = ui_file_xstrdup (stb, &length); do_cleanups (old_chain); @@ -1018,6 +1057,10 @@ check_types_equal (struct type *type1, struct type *type2, if (FIELD_BITPOS (*field1) != FIELD_BITPOS (*field2)) return Py_NE; break; + case FIELD_LOC_KIND_ENUMVAL: + if (FIELD_ENUMVAL (*field1) != FIELD_ENUMVAL (*field2)) + return Py_NE; + break; case FIELD_LOC_KIND_PHYSADDR: if (FIELD_STATIC_PHYSADDR (*field1) != FIELD_STATIC_PHYSADDR (*field2)) @@ -1055,7 +1098,6 @@ check_types_equal (struct type *type1, struct type *type2, if (TYPE_TARGET_TYPE (type1) != NULL) { struct type_equality_entry entry; - int added; if (TYPE_TARGET_TYPE (type2) == NULL) return Py_NE; @@ -1220,7 +1262,7 @@ typy_dealloc (PyObject *obj) if (type->next) type->next->prev = type->prev; - type->ob_type->tp_free (type); + Py_TYPE (type)->tp_free (type); } /* Return number of fields ("length" of the field dictionary). */ @@ -1255,7 +1297,6 @@ typy_getitem (PyObject *self, PyObject *key) struct type *type = ((type_object *) self)->type; char *field; int i; - volatile struct gdb_exception except; field = python_string_to_host_string (key); if (field == NULL) @@ -1271,7 +1312,7 @@ typy_getitem (PyObject *self, PyObject *key) for (i = 0; i < TYPE_NFIELDS (type); i++) { - char *t_field_name = TYPE_FIELD_NAME (type, i); + const char *t_field_name = TYPE_FIELD_NAME (type, i); if (t_field_name && (strcmp_iw (t_field_name, field) == 0)) { @@ -1317,7 +1358,6 @@ typy_has_key (PyObject *self, PyObject *args) struct type *type = ((type_object *) self)->type; const char *field; int i; - volatile struct gdb_exception except; if (!PyArg_ParseTuple (args, "s", &field)) return NULL; @@ -1332,7 +1372,7 @@ typy_has_key (PyObject *self, PyObject *args) for (i = 0; i < TYPE_NFIELDS (type); i++) { - char *t_field_name = TYPE_FIELD_NAME (type, i); + const char *t_field_name = TYPE_FIELD_NAME (type, i); if (t_field_name && (strcmp_iw (t_field_name, field) == 0)) Py_RETURN_TRUE; @@ -1414,7 +1454,6 @@ typy_iterator_iternext (PyObject *self) { typy_iterator_object *iter_obj = (typy_iterator_object *) self; struct type *type = iter_obj->source->type; - int i; PyObject *result; if (iter_obj->field < TYPE_NFIELDS (type)) @@ -1546,6 +1585,14 @@ static PyMethodDef type_object_methods[] = Return a type which represents an array of objects of this type.\n\ The bounds of the array are [LOW_BOUND, HIGH_BOUND] inclusive.\n\ If LOW_BOUND is omitted, a value of zero is used." }, + { "vector", typy_vector, METH_VARARGS, + "vector ([LOW_BOUND,] HIGH_BOUND) -> Type\n\ +Return a type which represents a vector of objects of this type.\n\ +The bounds of the array are [LOW_BOUND, HIGH_BOUND] inclusive.\n\ +If LOW_BOUND is omitted, a value of zero is used.\n\ +Vectors differ from arrays in that if the current language has C-style\n\ +arrays, vectors don't decay to a pointer to the first element.\n\ +They are first class values." }, { "__contains__", typy_has_key, METH_VARARGS, "T.__contains__(k) -> True if T has a field named k, else False" }, { "const", typy_const, METH_NOARGS, @@ -1610,7 +1657,9 @@ static PyNumberMethods type_object_as_number = { NULL, /* nb_add */ NULL, /* nb_subtract */ NULL, /* nb_multiply */ +#ifndef IS_PY3K NULL, /* nb_divide */ +#endif NULL, /* nb_remainder */ NULL, /* nb_divmod */ NULL, /* nb_power */ @@ -1624,12 +1673,19 @@ static PyNumberMethods type_object_as_number = { NULL, /* nb_and */ NULL, /* nb_xor */ NULL, /* nb_or */ +#ifdef IS_PY3K + NULL, /* nb_int */ + NULL, /* reserved */ +#else NULL, /* nb_coerce */ NULL, /* nb_int */ NULL, /* nb_long */ +#endif NULL, /* nb_float */ +#ifndef IS_PY3K NULL, /* nb_oct */ NULL /* nb_hex */ +#endif }; static PyMappingMethods typy_mapping = { @@ -1640,8 +1696,7 @@ static PyMappingMethods typy_mapping = { static PyTypeObject type_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Type", /*tp_name*/ sizeof (type_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ @@ -1681,10 +1736,16 @@ static PyTypeObject type_object_type = 0, /* tp_new */ }; +static PyGetSetDef field_object_getset[] = +{ + { "__dict__", gdb_py_generic_dict, NULL, + "The __dict__ for this field.", &field_object_type }, + { NULL } +}; + static PyTypeObject field_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Field", /*tp_name*/ sizeof (field_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ @@ -1713,7 +1774,7 @@ static PyTypeObject field_object_type = 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + field_object_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ @@ -1725,8 +1786,7 @@ static PyTypeObject field_object_type = }; static PyTypeObject type_iterator_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.TypeIterator", /*tp_name*/ sizeof (typy_iterator_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/py-utils.c b/contrib/gdb-7/gdb/python/py-utils.c index 3579720674..b280c8cc71 100644 --- a/contrib/gdb-7/gdb/python/py-utils.c +++ b/contrib/gdb-7/gdb/python/py-utils.c @@ -1,6 +1,6 @@ /* General utility routines for GDB/Python. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -54,7 +54,8 @@ make_cleanup_py_decref (PyObject *py) As an added bonus, the functions accepts a unicode string and returns it right away, so callers don't need to check which kind of string they've - got. + got. In Python 3, all strings are Unicode so this case is always the + one that applies. If the given object is not one of the mentioned string types, NULL is returned, with the TypeError python exception set. */ @@ -70,9 +71,10 @@ python_string_to_unicode (PyObject *obj) unicode_str = obj; Py_INCREF (obj); } - +#ifndef IS_PY3K else if (PyString_Check (obj)) unicode_str = PyUnicode_FromEncodedObject (obj, host_charset (), NULL); +#endif else { PyErr_SetString (PyExc_TypeError, @@ -99,7 +101,11 @@ unicode_to_encoded_string (PyObject *unicode_str, const char *charset) if (string == NULL) return NULL; +#ifdef IS_PY3K + result = xstrdup (PyBytes_AsString (string)); +#else result = xstrdup (PyString_AsString (string)); +#endif Py_DECREF (string); @@ -113,14 +119,8 @@ unicode_to_encoded_string (PyObject *unicode_str, const char *charset) static PyObject * unicode_to_encoded_python_string (PyObject *unicode_str, const char *charset) { - PyObject *string; - /* Translate string to named charset. */ - string = PyUnicode_AsEncodedString (unicode_str, charset, NULL); - if (string == NULL) - return NULL; - - return string; + return PyUnicode_AsEncodedString (unicode_str, charset, NULL); } /* Returns a newly allocated string with the contents of the given unicode @@ -139,7 +139,7 @@ unicode_to_target_string (PyObject *unicode_str) object converted to the target's charset. If an error occurs during the conversion, NULL will be returned and a python exception will be set. */ -PyObject * +static PyObject * unicode_to_target_python_string (PyObject *unicode_str) { return unicode_to_encoded_python_string (unicode_str, @@ -167,7 +167,9 @@ python_string_to_target_string (PyObject *obj) /* Converts a python string (8-bit or unicode) to a target string in the target's charset. Returns NULL on error, with a python exception - set. */ + set. + + In Python 3, the returned object is a "bytes" object (not a string). */ PyObject * python_string_to_target_python_string (PyObject *obj) { @@ -202,26 +204,17 @@ python_string_to_host_string (PyObject *obj) return result; } -/* Converts a target string of LENGTH bytes in the target's charset to a - Python Unicode string. If LENGTH is -1, convert until a null byte is found. - - Returns NULL on error, with a python exception set. */ -PyObject * -target_string_to_unicode (const gdb_byte *str, int length) -{ - if (length == -1) - length = strlen (str); - - return PyUnicode_Decode (str, length, target_charset (python_gdbarch), NULL); -} - /* Return true if OBJ is a Python string or unicode object, false otherwise. */ int gdbpy_is_string (PyObject *obj) { +#ifdef IS_PY3K + return PyUnicode_Check (obj); +#else return PyString_Check (obj) || PyUnicode_Check (obj); +#endif } /* Return the string representation of OBJ, i.e., str (obj). @@ -235,7 +228,11 @@ gdbpy_obj_to_string (PyObject *obj) if (str_obj != NULL) { +#ifdef IS_PY3K + char *msg = python_string_to_host_string (str_obj); +#else char *msg = xstrdup (PyString_AsString (str_obj)); +#endif Py_DECREF (str_obj); return msg; @@ -335,6 +332,11 @@ get_addr_from_python (PyObject *obj, CORE_ADDR *addr) PyObject * gdb_py_object_from_longest (LONGEST l) { +#ifdef IS_PY3K + if (sizeof (l) > sizeof (long)) + return PyLong_FromLongLong (l); + return PyLong_FromLong (l); +#else #ifdef HAVE_LONG_LONG /* Defined by Python. */ /* If we have 'long long', and the value overflows a 'long', use a Python Long; otherwise use a Python Int. */ @@ -343,6 +345,7 @@ gdb_py_object_from_longest (LONGEST l) return PyLong_FromLongLong (l); #endif return PyInt_FromLong (l); +#endif } /* Convert a ULONGEST to the appropriate Python object -- either an @@ -351,6 +354,11 @@ gdb_py_object_from_longest (LONGEST l) PyObject * gdb_py_object_from_ulongest (ULONGEST l) { +#ifdef IS_PY3K + if (sizeof (l) > sizeof (unsigned long)) + return PyLong_FromUnsignedLongLong (l); + return PyLong_FromUnsignedLong (l); +#else #ifdef HAVE_LONG_LONG /* Defined by Python. */ /* If we have 'long long', and the value overflows a 'long', use a Python Long; otherwise use a Python Int. */ @@ -362,6 +370,7 @@ gdb_py_object_from_ulongest (ULONGEST l) return PyLong_FromUnsignedLong (l); return PyInt_FromLong (l); +#endif } /* Like PyInt_AsLong, but returns 0 on failure, 1 on success, and puts @@ -373,3 +382,23 @@ gdb_py_int_as_long (PyObject *obj, long *result) *result = PyInt_AsLong (obj); return ! (*result == -1 && PyErr_Occurred ()); } + + + +/* Generic implementation of the __dict__ attribute for objects that + have a dictionary. The CLOSURE argument should be the type object. + This only handles positive values for tp_dictoffset. */ + +PyObject * +gdb_py_generic_dict (PyObject *self, void *closure) +{ + PyObject *result; + PyTypeObject *type_obj = closure; + char *raw_ptr; + + raw_ptr = (char *) self + type_obj->tp_dictoffset; + result = * (PyObject **) raw_ptr; + + Py_INCREF (result); + return result; +} diff --git a/contrib/gdb-7/gdb/python/py-value.c b/contrib/gdb-7/gdb/python/py-value.c index 19423eaf53..11cc038278 100644 --- a/contrib/gdb-7/gdb/python/py-value.c +++ b/contrib/gdb-7/gdb/python/py-value.c @@ -1,6 +1,6 @@ /* Python interface to values. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -28,6 +28,7 @@ #include "infcall.h" #include "expression.h" #include "cp-abi.h" +#include "python.h" #ifdef HAVE_PYTHON @@ -105,7 +106,7 @@ valpy_dealloc (PyObject *obj) Py_XDECREF (self->dynamic_type); - self->ob_type->tp_free (self); + Py_TYPE (self)->tp_free (self); } /* Helper to push a Value object on the global list. */ @@ -150,7 +151,7 @@ valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *keywords) } value_obj->value = value; - value_incref (value); + release_value_or_incref (value); value_obj->address = NULL; value_obj->type = NULL; value_obj->dynamic_type = NULL; @@ -174,23 +175,68 @@ preserve_python_values (struct objfile *objfile, htab_t copied_types) static PyObject * valpy_dereference (PyObject *self, PyObject *args) { - struct value *res_val = NULL; /* Initialize to appease gcc warning. */ volatile struct gdb_exception except; + PyObject *result = NULL; TRY_CATCH (except, RETURN_MASK_ALL) { + struct value *res_val; + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); + res_val = value_ind (((value_object *) self)->value); + result = value_to_value_object (res_val); + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); - return value_to_value_object (res_val); + return result; +} + +/* Given a value of a pointer type or a reference type, return the value + referenced. The difference between this function and valpy_dereference is + that the latter applies * unary operator to a value, which need not always + result in the value referenced. For example, for a value which is a reference + to an 'int' pointer ('int *'), valpy_dereference will result in a value of + type 'int' while valpy_referenced_value will result in a value of type + 'int *'. */ + +static PyObject * +valpy_referenced_value (PyObject *self, PyObject *args) +{ + volatile struct gdb_exception except; + PyObject *result = NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct value *self_val, *res_val; + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); + + self_val = ((value_object *) self)->value; + switch (TYPE_CODE (check_typedef (value_type (self_val)))) + { + case TYPE_CODE_PTR: + res_val = value_ind (self_val); + break; + case TYPE_CODE_REF: + res_val = coerce_ref (self_val); + break; + default: + error(_("Trying to get the referenced value from a value which is " + "neither a pointer nor a reference.")); + } + + result = value_to_value_object (res_val); + do_cleanups (cleanup); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return result; } /* Return "&value". */ static PyObject * valpy_get_address (PyObject *self, void *closure) { - struct value *res_val = NULL; /* Initialize to appease gcc warning. */ value_object *val_obj = (value_object *) self; volatile struct gdb_exception except; @@ -198,15 +244,19 @@ valpy_get_address (PyObject *self, void *closure) { TRY_CATCH (except, RETURN_MASK_ALL) { + struct value *res_val; + struct cleanup *cleanup + = make_cleanup_value_free_to_mark (value_mark ()); + res_val = value_addr (val_obj->value); + val_obj->address = value_to_value_object (res_val); + do_cleanups (cleanup); } if (except.reason < 0) { val_obj->address = Py_None; Py_INCREF (Py_None); } - else - val_obj->address = value_to_value_object (res_val); } Py_XINCREF (val_obj->address); @@ -248,6 +298,7 @@ valpy_get_dynamic_type (PyObject *self, void *closure) TRY_CATCH (except, RETURN_MASK_ALL) { struct value *val = obj->value; + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); type = value_type (val); CHECK_TYPEDEF (type); @@ -277,6 +328,8 @@ valpy_get_dynamic_type (PyObject *self, void *closure) /* Re-use object's static type. */ type = NULL; } + + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); @@ -311,7 +364,7 @@ valpy_lazy_string (PyObject *self, PyObject *args, PyObject *kw) struct value *value = ((value_object *) self)->value; const char *user_encoding = NULL; static char *keywords[] = { "encoding", "length", NULL }; - PyObject *str_obj; + PyObject *str_obj = NULL; volatile struct gdb_exception except; if (!PyArg_ParseTupleAndKeywords (args, kw, "|s" GDB_PY_LL_ARG, keywords, @@ -320,16 +373,20 @@ valpy_lazy_string (PyObject *self, PyObject *args, PyObject *kw) TRY_CATCH (except, RETURN_MASK_ALL) { + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); + if (TYPE_CODE (value_type (value)) == TYPE_CODE_PTR) value = value_ind (value); + + str_obj = gdbpy_create_lazy_string_object (value_address (value), length, + user_encoding, + value_type (value)); + + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); - str_obj = gdbpy_create_lazy_string_object (value_address (value), length, - user_encoding, - value_type (value)); - - return (PyObject *) str_obj; + return str_obj; } /* Implementation of gdb.Value.string ([encoding] [, errors] @@ -376,9 +433,8 @@ valpy_string (PyObject *self, PyObject *args, PyObject *kw) static PyObject * valpy_do_cast (PyObject *self, PyObject *args, enum exp_opcode op) { - PyObject *type_obj; + PyObject *type_obj, *result = NULL; 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)) @@ -395,6 +451,8 @@ valpy_do_cast (PyObject *self, PyObject *args, enum exp_opcode op) TRY_CATCH (except, RETURN_MASK_ALL) { struct value *val = ((value_object *) self)->value; + struct value *res_val; + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); if (op == UNOP_DYNAMIC_CAST) res_val = value_dynamic_cast (type, val); @@ -405,10 +463,13 @@ valpy_do_cast (PyObject *self, PyObject *args, enum exp_opcode op) gdb_assert (op == UNOP_CAST); res_val = value_cast (type, val); } + + result = value_to_value_object (res_val); + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); - return value_to_value_object (res_val); + return result; } /* Implementation of the "cast" method. */ @@ -451,8 +512,8 @@ valpy_getitem (PyObject *self, PyObject *key) { value_object *self_value = (value_object *) self; char *field = NULL; - struct value *res_val = NULL; volatile struct gdb_exception except; + PyObject *result = NULL; if (gdbpy_is_string (key)) { @@ -464,6 +525,8 @@ valpy_getitem (PyObject *self, PyObject *key) TRY_CATCH (except, RETURN_MASK_ALL) { struct value *tmp = self_value->value; + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); + struct value *res_val = NULL; if (field) res_val = value_struct_elt (&tmp, NULL, field, 0, NULL); @@ -489,12 +552,16 @@ valpy_getitem (PyObject *self, PyObject *key) res_val = value_subscript (tmp, value_as_long (idx)); } } + + if (res_val) + result = value_to_value_object (res_val); + do_cleanups (cleanup); } xfree (field); GDB_PY_HANDLE_EXCEPTION (except); - return res_val ? value_to_value_object (res_val) : NULL; + return result; } static int @@ -510,12 +577,13 @@ valpy_setitem (PyObject *self, PyObject *key, PyObject *value) static PyObject * valpy_call (PyObject *self, PyObject *args, PyObject *keywords) { - struct value *return_value = NULL; Py_ssize_t args_count; volatile struct gdb_exception except; struct value *function = ((value_object *) self)->value; struct value **vargs = NULL; struct type *ftype = NULL; + struct value *mark = value_mark (); + PyObject *result = NULL; TRY_CATCH (except, RETURN_MASK_ALL) { @@ -558,11 +626,16 @@ valpy_call (PyObject *self, PyObject *args, PyObject *keywords) TRY_CATCH (except, RETURN_MASK_ALL) { + struct cleanup *cleanup = make_cleanup_value_free_to_mark (mark); + struct value *return_value; + return_value = call_function_by_hand (function, args_count, vargs); + result = value_to_value_object (return_value); + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); - return value_to_value_object (return_value); + return result; } /* Called by the Python interpreter to obtain string representation @@ -687,12 +760,14 @@ enum valpy_opcode static PyObject * valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) { - struct value *res_val = NULL; /* Initialize to appease gcc warning. */ volatile struct gdb_exception except; + PyObject *result = NULL; TRY_CATCH (except, RETURN_MASK_ALL) { struct value *arg1, *arg2; + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); + struct value *res_val = NULL; /* If the gdb.Value object is the second operand, then it will be passed to us as the OTHER argument, and SELF will be an entirely different @@ -778,10 +853,15 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) res_val = value_binop (arg1, arg2, BINOP_BITWISE_XOR); break; } + + if (res_val) + result = value_to_value_object (res_val); + + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); - return res_val ? value_to_value_object (res_val) : NULL; + return result; } static PyObject * @@ -833,16 +913,22 @@ valpy_power (PyObject *self, PyObject *other, PyObject *unused) static PyObject * valpy_negative (PyObject *self) { - struct value *val = NULL; volatile struct gdb_exception except; + PyObject *result = NULL; TRY_CATCH (except, RETURN_MASK_ALL) { + /* Perhaps overkill, but consistency has some virtue. */ + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); + struct value *val; + val = value_neg (((value_object *) self)->value); + result = value_to_value_object (val); + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); - return value_to_value_object (val); + return result; } static PyObject * @@ -860,8 +946,12 @@ valpy_absolute (PyObject *self) TRY_CATCH (except, RETURN_MASK_ALL) { + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); + if (value_less (value, value_zero (value_type (value), not_lval))) isabs = 0; + + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); @@ -961,7 +1051,6 @@ static PyObject * valpy_richcompare (PyObject *self, PyObject *other, int op) { int result = 0; - struct value *value_other; volatile struct gdb_exception except; if (other == Py_None) @@ -985,6 +1074,9 @@ valpy_richcompare (PyObject *self, PyObject *other, int op) TRY_CATCH (except, RETURN_MASK_ALL) { + struct value *value_other, *mark = value_mark (); + struct cleanup *cleanup; + value_other = convert_value_from_python (other); if (value_other == NULL) { @@ -992,6 +1084,8 @@ valpy_richcompare (PyObject *self, PyObject *other, int op) break; } + cleanup = make_cleanup_value_free_to_mark (mark); + switch (op) { case Py_LT: result = value_less (((value_object *) self)->value, value_other); @@ -1020,6 +1114,8 @@ valpy_richcompare (PyObject *self, PyObject *other, int op) result = -1; break; } + + do_cleanups (cleanup); } GDB_PY_HANDLE_EXCEPTION (except); @@ -1044,6 +1140,7 @@ is_intlike (struct type *type, int ptr_ok) || (ptr_ok && TYPE_CODE (type) == TYPE_CODE_PTR)); } +#ifndef IS_PY3K /* Implements conversion to int. */ static PyObject * valpy_int (PyObject *self) @@ -1065,6 +1162,7 @@ valpy_int (PyObject *self) return gdb_py_object_from_longest (l); } +#endif /* Implements conversion to long. */ static PyObject * @@ -1123,7 +1221,7 @@ value_to_value_object (struct value *val) if (val_obj != NULL) { val_obj->value = val; - value_incref (val); + release_value_or_incref (val); val_obj->address = NULL; val_obj->type = NULL; val_obj->dynamic_type = NULL; @@ -1154,7 +1252,6 @@ struct value * convert_value_from_python (PyObject *obj) { struct value *value = NULL; /* -Wall */ - struct cleanup *old; volatile struct gdb_exception except; int cmp; @@ -1223,6 +1320,8 @@ convert_value_from_python (PyObject *obj) s = python_string_to_target_string (obj); if (s != NULL) { + struct cleanup *old; + old = make_cleanup (xfree, s); value = value_cstring (s, strlen (s), builtin_type_pychar); do_cleanups (old); @@ -1238,9 +1337,14 @@ convert_value_from_python (PyObject *obj) value = value_copy (((value_object *) result)->value); } else +#ifdef IS_PY3K + PyErr_Format (PyExc_TypeError, + _("Could not convert Python object: %S."), obj); +#else PyErr_Format (PyExc_TypeError, _("Could not convert Python object: %s."), PyString_AsString (PyObject_Str (obj))); +#endif } if (except.reason < 0) { @@ -1324,6 +1428,8 @@ Cast the value to the supplied type, as if by the C++\n\ reinterpret_cast operator." }, { "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." }, + { "referenced_value", valpy_referenced_value, METH_NOARGS, + "Return the value referenced by a TYPE_CODE_REF or TYPE_CODE_PTR value." }, { "lazy_string", (PyCFunction) valpy_lazy_string, METH_VARARGS | METH_KEYWORDS, "lazy_string ([encoding] [, length]) -> lazy_string\n\ @@ -1340,7 +1446,9 @@ static PyNumberMethods value_object_as_number = { valpy_add, valpy_subtract, valpy_multiply, +#ifndef IS_PY3K valpy_divide, +#endif valpy_remainder, NULL, /* nb_divmod */ valpy_power, /* nb_power */ @@ -1354,12 +1462,31 @@ static PyNumberMethods value_object_as_number = { valpy_and, /* nb_and */ valpy_xor, /* nb_xor */ valpy_or, /* nb_or */ +#ifdef IS_PY3K + valpy_long, /* nb_int */ + NULL, /* reserved */ +#else NULL, /* nb_coerce */ valpy_int, /* nb_int */ valpy_long, /* nb_long */ +#endif valpy_float, /* nb_float */ +#ifndef IS_PY3K NULL, /* nb_oct */ - NULL /* nb_hex */ + NULL, /* nb_hex */ +#endif + NULL, /* nb_inplace_add */ + NULL, /* nb_inplace_subtract */ + NULL, /* nb_inplace_multiply */ + NULL, /* nb_inplace_remainder */ + NULL, /* nb_inplace_power */ + NULL, /* nb_inplace_lshift */ + NULL, /* nb_inplace_rshift */ + NULL, /* nb_inplace_and */ + NULL, /* nb_inplace_xor */ + NULL, /* nb_inplace_or */ + NULL, /* nb_floor_divide */ + valpy_divide /* nb_true_divide */ }; static PyMappingMethods value_object_as_mapping = { @@ -1369,8 +1496,7 @@ static PyMappingMethods value_object_as_mapping = { }; PyTypeObject value_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT (NULL, 0) "gdb.Value", /*tp_name*/ sizeof (value_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff --git a/contrib/gdb-7/gdb/python/python-config.py b/contrib/gdb-7/gdb/python/python-config.py index 75ed2d2183..c2b2969c39 100644 --- a/contrib/gdb-7/gdb/python/python-config.py +++ b/contrib/gdb-7/gdb/python/python-config.py @@ -10,8 +10,8 @@ valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', 'ldflags', 'help'] def exit_with_usage(code=1): - print >>sys.stderr, "Usage: %s [%s]" % (sys.argv[0], - '|'.join('--'+opt for opt in valid_opts)) + sys.stderr.write ("Usage: %s [%s]\n" % (sys.argv[0], + '|'.join('--'+opt for opt in valid_opts))) sys.exit(code) try: @@ -24,6 +24,7 @@ if not opts: pyver = sysconfig.get_config_var('VERSION') getvar = sysconfig.get_config_var +abiflags = getattr (sys, "abiflags", "") opt_flags = [flag for (flag, val) in opts] @@ -44,17 +45,17 @@ def to_unix_path(path): for opt in opt_flags: if opt == '--prefix': - print to_unix_path(sysconfig.PREFIX) + print (to_unix_path(sysconfig.PREFIX)) elif opt == '--exec-prefix': - print to_unix_path(sysconfig.EXEC_PREFIX) + print (to_unix_path(sysconfig.EXEC_PREFIX)) elif opt in ('--includes', '--cflags'): flags = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)] if opt == '--cflags': flags.extend(getvar('CFLAGS').split()) - print to_unix_path(' '.join(flags)) + print (to_unix_path(' '.join(flags))) elif opt in ('--libs', '--ldflags'): libs = [] @@ -62,7 +63,7 @@ for opt in opt_flags: libs.extend(getvar('LIBS').split()) if getvar('SYSLIBS') is not None: libs.extend(getvar('SYSLIBS').split()) - libs.append('-lpython'+pyver) + libs.append('-lpython'+pyver + abiflags) # add the prefix/lib/pythonX.Y/config dir, but only if there is no # shared library in prefix/lib/. if opt == '--ldflags': @@ -73,5 +74,5 @@ for opt in opt_flags: libs.insert(0, '-L' + sysconfig.PREFIX + '/libs') if getvar('LINKFORSHARED') is not None: libs.extend(getvar('LINKFORSHARED').split()) - print to_unix_path(' '.join(libs)) + print (to_unix_path(' '.join(libs))) diff --git a/contrib/gdb-7/gdb/python/python-internal.h b/contrib/gdb-7/gdb/python/python-internal.h index 328e5d8787..ea97226f47 100644 --- a/contrib/gdb-7/gdb/python/python-internal.h +++ b/contrib/gdb-7/gdb/python/python-internal.h @@ -1,6 +1,6 @@ /* Gdb/Python header for private use by Python module. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -41,6 +41,11 @@ around technique as above. */ #undef _FILE_OFFSET_BITS +/* A kludge to avoid redefinition of snprintf on Windows by pyerrors.h. */ +#if defined(_WIN32) && defined(HAVE_DECL_SNPRINTF) +#define HAVE_SNPRINTF 1 +#endif + /* Request clean size types from Python. */ #define PY_SSIZE_T_CLEAN @@ -49,6 +54,25 @@ from including our python/python.h header file. */ #include #include + +#if PY_MAJOR_VERSION >= 3 +#define IS_PY3K 1 +#endif + +#ifdef IS_PY3K +#define Py_TPFLAGS_HAVE_ITER 0 +#define Py_TPFLAGS_CHECKTYPES 0 + +#define PyInt_Check PyLong_Check +#define PyInt_FromLong PyLong_FromLong +#define PyInt_AsLong PyLong_AsLong + +#define PyString_FromString PyUnicode_FromString +#define PyString_Decode PyUnicode_Decode +#define PyString_FromFormat PyUnicode_FromFormat +#define PyString_Check PyUnicode_Check +#endif + #if HAVE_LIBPYTHON2_4 /* 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 @@ -57,6 +81,18 @@ typedef int Py_ssize_t; #endif +#ifndef PyVarObject_HEAD_INIT +/* Python 2.4 does not define PyVarObject_HEAD_INIT. */ +#define PyVarObject_HEAD_INIT(type, size) \ + PyObject_HEAD_INIT(type) size, + +#endif + +#ifndef Py_TYPE +/* Python 2.4 does not define Py_TYPE. */ +#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) +#endif + /* If Python.h does not define WITH_THREAD, then the various GIL-related functions will not be defined. However, PyGILState_STATE will be. */ @@ -114,6 +150,7 @@ struct bpstats; struct inferior; extern PyObject *gdb_module; +extern PyObject *gdb_python_module; extern PyTypeObject value_object_type; extern PyTypeObject block_object_type; extern PyTypeObject symbol_object_type; @@ -121,6 +158,7 @@ extern PyTypeObject event_object_type; extern PyTypeObject events_object_type; extern PyTypeObject stop_event_object_type; extern PyTypeObject breakpoint_object_type; +extern PyTypeObject frame_object_type; typedef struct breakpoint_object { @@ -217,6 +255,8 @@ PyObject *pspy_get_printers (PyObject *, void *); PyObject *objfile_to_objfile_object (struct objfile *); PyObject *objfpy_get_printers (PyObject *, void *); +PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch); + thread_object *create_thread_object (struct thread_info *tp); thread_object *find_thread_object (ptid_t ptid); PyObject *find_inferior_object (int pid); @@ -230,7 +270,9 @@ struct type *type_object_to_type (PyObject *obj); struct symtab *symtab_object_to_symtab (PyObject *obj); struct symtab_and_line *sal_object_to_symtab_and_line (PyObject *obj); struct frame_info *frame_object_to_frame_info (PyObject *frame_obj); +struct gdbarch *arch_object_to_gdbarch (PyObject *obj); +void gdbpy_initialize_gdb_readline (void); void gdbpy_initialize_auto_load (void); void gdbpy_initialize_values (void); void gdbpy_initialize_frames (void); @@ -259,6 +301,7 @@ void gdbpy_initialize_continue_event (void); void gdbpy_initialize_exited_event (void); void gdbpy_initialize_thread_event (void); void gdbpy_initialize_new_objfile_event (void); +void gdbpy_initialize_arch (void); struct cleanup *make_cleanup_py_decref (PyObject *py); @@ -289,15 +332,14 @@ extern const struct language_defn *python_language; void gdbpy_print_stack (void); -void source_python_script_for_objfile (struct objfile *objfile, - const char *file); +void source_python_script_for_objfile (struct objfile *objfile, FILE *file, + const char *filename); PyObject *python_string_to_unicode (PyObject *obj); char *unicode_to_target_string (PyObject *unicode_str); char *python_string_to_target_string (PyObject *obj); PyObject *python_string_to_target_python_string (PyObject *obj); 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); char *gdbpy_obj_to_string (PyObject *obj); char *gdbpy_exception_to_string (PyObject *ptype, PyObject *pvalue); @@ -341,4 +383,6 @@ PyObject *gdb_py_object_from_longest (LONGEST l); PyObject *gdb_py_object_from_ulongest (ULONGEST l); int gdb_py_int_as_long (PyObject *, long *); +PyObject *gdb_py_generic_dict (PyObject *self, void *closure); + #endif /* GDB_PYTHON_INTERNAL_H */ diff --git a/contrib/gdb-7/gdb/python/python.c b/contrib/gdb-7/gdb/python/python.c index 6611c82c85..67d06e5364 100644 --- a/contrib/gdb-7/gdb/python/python.c +++ b/contrib/gdb-7/gdb/python/python.c @@ -1,6 +1,6 @@ /* General python/gdb code - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -32,6 +32,7 @@ #include "serial.h" #include "readline/tilde.h" #include "python.h" +#include "cli/cli-utils.h" #include @@ -41,7 +42,7 @@ static const char python_excp_full[] = "full"; static const char python_excp_message[] = "message"; /* "set python print-stack" choices. */ -static const char *python_excp_enums[] = +static const char *const python_excp_enums[] = { python_excp_none, python_excp_full, @@ -70,10 +71,16 @@ static const char *gdbpy_should_print_stack = python_excp_message; #include "gdbthread.h" #include "observer.h" #include "interps.h" +#include "event-top.h" static PyMethodDef GdbMethods[]; +#ifdef IS_PY3K +static struct PyModuleDef GdbModuleDef; +#endif + PyObject *gdb_module; +PyObject *gdb_python_module; /* Some string constants we may wish to use. */ PyObject *gdbpy_to_string_cst; @@ -151,34 +158,126 @@ ensure_python_env (struct gdbarch *gdbarch, return make_cleanup (restore_python_env, env); } -/* A wrapper around PyRun_SimpleFile. FILENAME is the name of - the Python script to run. - - One of the parameters of PyRun_SimpleFile is a FILE *. - The problem is that type FILE is extremely system and compiler - dependent. So, unless the Python library has been compiled using - the same build environment as GDB, we run the risk of getting - a crash due to inconsistencies between the definition used by GDB, - and the definition used by Python. A mismatch can very likely - lead to a crash. - - There is also the situation where the Python library and GDB - are using two different versions of the C runtime library. - This is particularly visible on Windows, where few users would - build Python themselves (this is no trivial task on this platform), - and thus use binaries built by someone else instead. Python, - being built with VC, would use one version of the msvcr DLL - (Eg. msvcr100.dll), while MinGW uses msvcrt.dll. A FILE * - from one runtime does not necessarily operate correctly in +/* Clear the quit flag. */ + +void +clear_quit_flag (void) +{ + /* This clears the flag as a side effect. */ + PyOS_InterruptOccurred (); +} + +/* Set the quit flag. */ + +void +set_quit_flag (void) +{ + PyErr_SetInterrupt (); +} + +/* Return true if the quit flag has been set, false otherwise. */ + +int +check_quit_flag (void) +{ + return PyOS_InterruptOccurred (); +} + +/* Evaluate a Python command like PyRun_SimpleString, but uses + Py_single_input which prints the result of expressions, and does + not automatically print the stack on errors. */ + +static int +eval_python_command (const char *command) +{ + PyObject *m, *d, *v; + + m = PyImport_AddModule ("__main__"); + if (m == NULL) + return -1; + + d = PyModule_GetDict (m); + if (d == NULL) + return -1; + v = PyRun_StringFlags (command, Py_single_input, d, d, NULL); + if (v == NULL) + return -1; + + Py_DECREF (v); +#ifndef IS_PY3K + if (Py_FlushLine ()) + PyErr_Clear (); +#endif + + return 0; +} + +/* Implementation of the gdb "python-interactive" command. */ + +static void +python_interactive_command (char *arg, int from_tty) +{ + struct cleanup *cleanup; + int err; + + cleanup = make_cleanup_restore_integer (&interpreter_async); + interpreter_async = 0; + + arg = skip_spaces (arg); + + ensure_python_env (get_current_arch (), current_language); + + if (arg && *arg) + { + int len = strlen (arg); + char *script = xmalloc (len + 2); + + strcpy (script, arg); + script[len] = '\n'; + script[len + 1] = '\0'; + err = eval_python_command (script); + xfree (script); + } + else + { + err = PyRun_InteractiveLoop (instream, ""); + dont_repeat (); + } + + if (err) + { + gdbpy_print_stack (); + error (_("Error while executing Python code.")); + } + + do_cleanups (cleanup); +} + +/* A wrapper around PyRun_SimpleFile. FILE is the Python script to run + named FILENAME. + + On Windows hosts few users would build Python themselves (this is no + trivial task on this platform), and thus use binaries built by + someone else instead. There may happen situation where the Python + library and GDB are using two different versions of the C runtime + library. Python, being built with VC, would use one version of the + msvcr DLL (Eg. msvcr100.dll), while MinGW uses msvcrt.dll. + A FILE * from one runtime does not necessarily operate correctly in the other runtime. - To work around this potential issue, we create the FILE object - using Python routines, thus making sure that it is compatible - with the Python library. */ + To work around this potential issue, we create on Windows hosts the + FILE object using Python routines, thus making sure that it is + compatible with the Python library. */ static void -python_run_simple_file (const char *filename) +python_run_simple_file (FILE *file, const char *filename) { +#ifndef _WIN32 + + PyRun_SimpleFile (file, filename); + +#else /* _WIN32 */ + char *full_path; PyObject *python_file; struct cleanup *cleanup; @@ -198,6 +297,8 @@ python_run_simple_file (const char *filename) make_cleanup_py_decref (python_file); PyRun_SimpleFile (PyFile_AsFile (python_file), filename); do_cleanups (cleanup); + +#endif /* _WIN32 */ } /* Given a command_line, return a command string suitable for passing @@ -266,8 +367,7 @@ python_command (char *arg, int from_tty) make_cleanup_restore_integer (&interpreter_async); interpreter_async = 0; - while (arg && *arg && isspace (*arg)) - ++arg; + arg = skip_spaces (arg); if (arg && *arg) { if (PyRun_SimpleString (arg)) @@ -504,7 +604,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args) appease gcc. */ struct symtab_and_line sal; const char *arg = NULL; - char *copy = NULL; + char *copy_to_free = NULL, *copy = NULL; struct cleanup *cleanups; PyObject *result = NULL; PyObject *return_result = NULL; @@ -516,14 +616,14 @@ gdbpy_decode_line (PyObject *self, PyObject *args) cleanups = make_cleanup (null_cleanup, NULL); + sals.sals = NULL; TRY_CATCH (except, RETURN_MASK_ALL) { if (arg) { copy = xstrdup (arg); - make_cleanup (xfree, copy); + copy_to_free = copy; sals = decode_line_1 (©, 0, 0, 0); - make_cleanup (xfree, sals.sals); } else { @@ -533,6 +633,13 @@ gdbpy_decode_line (PyObject *self, PyObject *args) sals.nelts = 1; } } + + if (sals.sals != NULL && sals.sals != &sal) + { + make_cleanup (xfree, copy_to_free); + make_cleanup (xfree, sals.sals); + } + if (except.reason < 0) { do_cleanups (cleanups); @@ -550,7 +657,6 @@ gdbpy_decode_line (PyObject *self, PyObject *args) for (i = 0; i < sals.nelts; ++i) { PyObject *obj; - char *str; obj = symtab_and_line_to_sal_object (sals.sals[i]); if (! obj) @@ -576,7 +682,16 @@ gdbpy_decode_line (PyObject *self, PyObject *args) } if (copy && strlen (copy) > 0) - unparsed = PyString_FromString (copy); + { + unparsed = PyString_FromString (copy); + if (unparsed == NULL) + { + Py_DECREF (result); + Py_DECREF (return_result); + return_result = NULL; + goto error; + } + } else { unparsed = Py_None; @@ -586,13 +701,10 @@ gdbpy_decode_line (PyObject *self, PyObject *args) PyTuple_SetItem (return_result, 0, unparsed); PyTuple_SetItem (return_result, 1, result); + error: do_cleanups (cleanups); return return_result; - - error: - do_cleanups (cleanups); - return NULL; } /* Parse a string and evaluate it as an expression. */ @@ -608,29 +720,52 @@ gdbpy_parse_and_eval (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - char *copy = xstrdup (expr_str); - struct cleanup *cleanup = make_cleanup (xfree, copy); - - result = parse_and_eval (copy); - do_cleanups (cleanup); + result = parse_and_eval (expr_str); } GDB_PY_HANDLE_EXCEPTION (except); return value_to_value_object (result); } +/* Implementation of gdb.find_pc_line function. + Returns the gdb.Symtab_and_line object corresponding to a PC value. */ + +static PyObject * +gdbpy_find_pc_line (PyObject *self, PyObject *args) +{ + gdb_py_ulongest pc_llu; + volatile struct gdb_exception except; + PyObject *result = NULL; /* init for gcc -Wall */ + + if (!PyArg_ParseTuple (args, GDB_PY_LLU_ARG, &pc_llu)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct symtab_and_line sal; + CORE_ADDR pc; + + pc = (CORE_ADDR) pc_llu; + sal = find_pc_line (pc, 0); + result = symtab_and_line_to_sal_object (sal); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return result; +} + /* Read a file as Python code. - FILE is the name of the file. + FILE is the file to run. FILENAME is name of the file FILE. This does not throw any errors. If an exception occurs python will print the traceback and clear the error indicator. */ void -source_python_script (const char *file) +source_python_script (FILE *file, const char *filename) { struct cleanup *cleanup; cleanup = ensure_python_env (get_current_arch (), current_language); - python_run_simple_file (file); + python_run_simple_file (file, filename); do_cleanups (cleanup); } @@ -664,7 +799,6 @@ static void gdbpy_run_events (struct serial *scb, void *context) { struct cleanup *cleanup; - int r; cleanup = ensure_python_env (get_current_arch (), current_language); @@ -757,11 +891,12 @@ before_prompt_hook (const char *current_gdb_prompt) cleanup = ensure_python_env (get_current_arch (), current_language); - if (PyObject_HasAttrString (gdb_module, "prompt_hook")) + if (gdb_python_module + && PyObject_HasAttrString (gdb_python_module, "prompt_hook")) { PyObject *hook; - hook = PyObject_GetAttrString (gdb_module, "prompt_hook"); + hook = PyObject_GetAttrString (gdb_python_module, "prompt_hook"); if (hook == NULL) goto fail; @@ -834,26 +969,31 @@ gdbpy_write (PyObject *self, PyObject *args, PyObject *kw) const char *arg; static char *keywords[] = {"text", "stream", NULL }; int stream_type = 0; + volatile struct gdb_exception except; if (! PyArg_ParseTupleAndKeywords (args, kw, "s|i", keywords, &arg, &stream_type)) return NULL; - switch (stream_type) + TRY_CATCH (except, RETURN_MASK_ALL) { - case 1: - { - fprintf_filtered (gdb_stderr, "%s", arg); - break; - } - case 2: - { - fprintf_filtered (gdb_stdlog, "%s", arg); - break; - } - default: - fprintf_filtered (gdb_stdout, "%s", arg); + switch (stream_type) + { + case 1: + { + fprintf_filtered (gdb_stderr, "%s", arg); + break; + } + case 2: + { + fprintf_filtered (gdb_stdlog, "%s", arg); + break; + } + default: + fprintf_filtered (gdb_stdout, "%s", arg); + } } + GDB_PY_HANDLE_EXCEPTION (except); Py_RETURN_NONE; } @@ -898,6 +1038,8 @@ gdbpy_flush (PyObject *self, PyObject *args, PyObject *kw) void gdbpy_print_stack (void) { + volatile struct gdb_exception except; + /* Print "none", just clear exception. */ if (gdbpy_should_print_stack == python_excp_none) { @@ -910,7 +1052,10 @@ gdbpy_print_stack (void) /* PyErr_Print doesn't necessarily end output with a newline. This works because Python's stdout/stderr is fed through printf_filtered. */ - begin_line (); + TRY_CATCH (except, RETURN_MASK_ALL) + { + begin_line (); + } } /* Print "message", just error print message. */ else @@ -923,17 +1068,21 @@ gdbpy_print_stack (void) /* Fetch the error message contained within ptype, pvalue. */ msg = gdbpy_exception_to_string (ptype, pvalue); type = gdbpy_obj_to_string (ptype); - if (msg == NULL) + + TRY_CATCH (except, RETURN_MASK_ALL) { - /* An error occurred computing the string representation of the - error message. */ - fprintf_filtered (gdb_stderr, - _("Error occurred computing Python error" \ - "message.\n")); + if (msg == NULL) + { + /* An error occurred computing the string representation of the + error message. */ + fprintf_filtered (gdb_stderr, + _("Error occurred computing Python error" \ + "message.\n")); + } + else + fprintf_filtered (gdb_stderr, "Python Exception %s %s: \n", + type, msg); } - else - fprintf_filtered (gdb_stderr, "Python Exception %s %s: \n", - type, msg); Py_XDECREF (ptype); Py_XDECREF (pvalue); @@ -991,19 +1140,20 @@ gdbpy_progspaces (PyObject *unused1, PyObject *unused2) source_python_script_for_objfile; it is NULL at other times. */ static struct objfile *gdbpy_current_objfile; -/* Set the current objfile to OBJFILE and then read FILE as Python code. - This does not throw any errors. If an exception occurs python will print - the traceback and clear the error indicator. */ +/* Set the current objfile to OBJFILE and then read FILE named FILENAME + as Python code. This does not throw any errors. If an exception + occurs python will print the traceback and clear the error indicator. */ void -source_python_script_for_objfile (struct objfile *objfile, const char *file) +source_python_script_for_objfile (struct objfile *objfile, FILE *file, + const char *filename) { struct cleanup *cleanups; cleanups = ensure_python_env (get_objfile_arch (objfile), current_language); gdbpy_current_objfile = objfile; - python_run_simple_file (file); + python_run_simple_file (file, filename); do_cleanups (cleanups); gdbpy_current_objfile = NULL; @@ -1051,15 +1201,134 @@ gdbpy_objfiles (PyObject *unused1, PyObject *unused2) return list; } +/* Compute the list of active type printers and return it. The result + of this function can be passed to apply_type_printers, and should + be freed by free_type_printers. */ + +void * +start_type_printers (void) +{ + struct cleanup *cleanups; + PyObject *type_module, *func, *result_obj = NULL; + + cleanups = ensure_python_env (get_current_arch (), current_language); + + type_module = PyImport_ImportModule ("gdb.types"); + if (type_module == NULL) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (type_module); + + func = PyObject_GetAttrString (type_module, "get_type_recognizers"); + if (func == NULL) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (func); + + result_obj = PyObject_CallFunctionObjArgs (func, (char *) NULL); + if (result_obj == NULL) + gdbpy_print_stack (); + + done: + do_cleanups (cleanups); + return result_obj; +} + +/* If TYPE is recognized by some type printer, return a newly + allocated string holding the type's replacement name. The caller + is responsible for freeing the string. Otherwise, return NULL. + + This function has a bit of a funny name, since it actually applies + recognizers, but this seemed clearer given the start_type_printers + and free_type_printers functions. */ + +char * +apply_type_printers (void *printers, struct type *type) +{ + struct cleanup *cleanups; + PyObject *type_obj, *type_module, *func, *result_obj; + PyObject *printers_obj = printers; + char *result = NULL; + + if (printers_obj == NULL) + return NULL; + + cleanups = ensure_python_env (get_current_arch (), current_language); + + type_obj = type_to_type_object (type); + if (type_obj == NULL) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (type_obj); + + type_module = PyImport_ImportModule ("gdb.types"); + if (type_module == NULL) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (type_module); + + func = PyObject_GetAttrString (type_module, "apply_type_recognizers"); + if (func == NULL) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (func); + + result_obj = PyObject_CallFunctionObjArgs (func, printers_obj, + type_obj, (char *) NULL); + if (result_obj == NULL) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (result_obj); + + if (result_obj != Py_None) + { + result = python_string_to_host_string (result_obj); + if (result == NULL) + gdbpy_print_stack (); + } + + done: + do_cleanups (cleanups); + return result; +} + +/* Free the result of start_type_printers. */ + +void +free_type_printers (void *arg) +{ + struct cleanup *cleanups; + PyObject *printers = arg; + + if (printers == NULL) + return; + + cleanups = ensure_python_env (get_current_arch (), current_language); + Py_DECREF (printers); + do_cleanups (cleanups); +} + #else /* HAVE_PYTHON */ -/* Dummy implementation of the gdb "python" command. */ +/* Dummy implementation of the gdb "python-interactive" and "python" + command. */ static void -python_command (char *arg, int from_tty) +python_interactive_command (char *arg, int from_tty) { - while (arg && *arg && isspace (*arg)) - ++arg; + arg = skip_spaces (arg); if (arg && *arg) error (_("Python scripting is not supported in this copy of GDB.")); else @@ -1072,6 +1341,12 @@ python_command (char *arg, int from_tty) } } +static void +python_command (char *arg, int from_tty) +{ + python_interactive_command (arg, from_tty); +} + void eval_python_from_control_command (struct command_line *cmd) { @@ -1079,7 +1354,7 @@ eval_python_from_control_command (struct command_line *cmd) } void -source_python_script (const char *file) +source_python_script (FILE *file, const char *filename) { throw_error (UNSUPPORTED_ERROR, _("Python scripting is not supported in this copy of GDB.")); @@ -1101,59 +1376,24 @@ gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj) "scripting is not supported.")); } -#endif /* HAVE_PYTHON */ - - -/* Support for "mt set python print-stack on|off" is present in gdb 7.4 - to not break Eclipse. - ref: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367788. */ - -/* Lists for 'maint set python' commands. */ - -static struct cmd_list_element *maint_set_python_list; -static struct cmd_list_element *maint_show_python_list; - -/* Function for use by 'maint set python' prefix command. */ - -static void -maint_set_python (char *args, int from_tty) +void * +start_type_printers (void) { - help_list (maint_set_python_list, "maintenance set python ", - class_deprecated, gdb_stdout); + return NULL; } -/* Function for use by 'maint show python' prefix command. */ - -static void -maint_show_python (char *args, int from_tty) +char * +apply_type_printers (void *ignore, struct type *type) { - cmd_show_list (maint_show_python_list, from_tty, ""); + return NULL; } -/* True if we should print the stack when catching a Python error, - false otherwise. */ -static int gdbpy_should_print_stack_deprecated = 0; - -static void -set_maint_python_print_stack (char *args, int from_tty, - struct cmd_list_element *e) +void +free_type_printers (void *arg) { - if (gdbpy_should_print_stack_deprecated) - gdbpy_should_print_stack = python_excp_full; - else - gdbpy_should_print_stack = python_excp_none; } -static void -show_maint_python_print_stack (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) -{ - fprintf_filtered (file, - _("The mode of Python stack printing on error is" - " \"%s\".\n"), - gdbpy_should_print_stack == python_excp_full - ? "on" : "off"); -} +#endif /* HAVE_PYTHON */ @@ -1181,14 +1421,66 @@ user_show_python (char *args, int from_tty) /* Initialize the Python code. */ +#ifdef HAVE_PYTHON + +/* This is installed as a final cleanup and cleans up the + interpreter. This lets Python's 'atexit' work. */ + +static void +finalize_python (void *ignore) +{ + /* We don't use ensure_python_env here because if we ever ran the + cleanup, gdb would crash -- because the cleanup calls into the + Python interpreter, which we are about to destroy. It seems + clearer to make the needed calls explicitly here than to create a + cleanup and then mysteriously discard it. */ + (void) PyGILState_Ensure (); + python_gdbarch = target_gdbarch (); + python_language = current_language; + + Py_Finalize (); +} +#endif + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_python; void _initialize_python (void) { - char *cmd_name; - struct cmd_list_element *cmd; + char *progname; +#ifdef IS_PY3K + int i; + size_t progsize, count; + char *oldloc; + wchar_t *progname_copy; +#endif + + add_com ("python-interactive", class_obscure, + python_interactive_command, +#ifdef HAVE_PYTHON + _("\ +Start an interactive Python prompt.\n\ +\n\ +To return to GDB, type the EOF character (e.g., Ctrl-D on an empty\n\ +prompt).\n\ +\n\ +Alternatively, a single-line Python command can be given as an\n\ +argument, and if the command is an expression, the result will be\n\ +printed. For example:\n\ +\n\ + (gdb) python-interactive 2 + 3\n\ + 5\n\ +") +#else /* HAVE_PYTHON */ + _("\ +Start a Python interactive prompt.\n\ +\n\ +Python scripting is not supported in this copy of GDB.\n\ +This command is only a placeholder.") +#endif /* HAVE_PYTHON */ + ); + add_com_alias ("pi", "python-interactive", class_obscure, 1); add_com ("python", class_obscure, python_command, #ifdef HAVE_PYTHON @@ -1210,34 +1502,7 @@ Python scripting is not supported in this copy of GDB.\n\ This command is only a placeholder.") #endif /* HAVE_PYTHON */ ); - - add_prefix_cmd ("python", no_class, maint_show_python, - _("Prefix command for python maintenance settings."), - &maint_show_python_list, "maintenance show python ", 0, - &maintenance_show_cmdlist); - add_prefix_cmd ("python", no_class, maint_set_python, - _("Prefix command for python maintenance settings."), - &maint_set_python_list, "maintenance set python ", 0, - &maintenance_set_cmdlist); - - add_setshow_boolean_cmd ("print-stack", class_maintenance, - &gdbpy_should_print_stack_deprecated, _("\ -Enable or disable printing of Python stack dump on error."), _("\ -Show whether Python stack will be printed on error."), _("\ -Enables or disables printing of Python stack traces."), - set_maint_python_print_stack, - show_maint_python_print_stack, - &maint_set_python_list, - &maint_show_python_list); - - /* Deprecate maint set/show python print-stack in favour of - non-maintenance alternatives. */ - cmd_name = "print-stack"; - cmd = lookup_cmd (&cmd_name, maint_set_python_list, "", -1, 0); - deprecate_cmd (cmd, "set python print-stack"); - cmd_name = "print-stack"; /* Reset name. */ - cmd = lookup_cmd (&cmd_name, maint_show_python_list, "", -1, 0); - deprecate_cmd (cmd, "show python print-stack"); + add_com_alias ("py", "python", class_obscure, 1); /* Add set/show python print-stack. */ add_prefix_cmd ("python", no_class, user_show_python, @@ -1269,14 +1534,50 @@ message == an error message without a stack will be printed."), /foo/bin/python /foo/lib/pythonX.Y/... This must be done before calling Py_Initialize. */ - Py_SetProgramName (concat (ldirname (python_libdir), SLASH_STRING, "bin", - SLASH_STRING, "python", NULL)); + progname = concat (ldirname (python_libdir), SLASH_STRING, "bin", + SLASH_STRING, "python", NULL); +#ifdef IS_PY3K + oldloc = setlocale (LC_ALL, NULL); + setlocale (LC_ALL, ""); + progsize = strlen (progname); + if (progsize == (size_t) -1) + { + fprintf (stderr, "Could not convert python path to string\n"); + return; + } + progname_copy = PyMem_Malloc ((progsize + 1) * sizeof (wchar_t)); + if (!progname_copy) + { + fprintf (stderr, "out of memory\n"); + return; + } + count = mbstowcs (progname_copy, progname, progsize + 1); + if (count == (size_t) -1) + { + fprintf (stderr, "Could not convert python path to string\n"); + return; + } + setlocale (LC_ALL, oldloc); + + /* Note that Py_SetProgramName expects the string it is passed to + remain alive for the duration of the program's execution, so + it is not freed after this call. */ + Py_SetProgramName (progname_copy); +#else + Py_SetProgramName (progname); +#endif #endif Py_Initialize (); PyEval_InitThreads (); - gdb_module = Py_InitModule ("gdb", GdbMethods); +#ifdef IS_PY3K + gdb_module = PyModule_Create (&GdbModuleDef); + /* Add _gdb module to the list of known built-in modules. */ + _PyImport_FixupBuiltin (gdb_module, "_gdb"); +#else + gdb_module = Py_InitModule ("_gdb", GdbMethods); +#endif /* The casts to (char*) are for python 2.4. */ PyModule_AddStringConstant (gdb_module, "VERSION", (char*) version); @@ -1288,17 +1589,6 @@ message == an error message without a stack will be printed."), PyModule_AddIntConstant (gdb_module, "STDOUT", 0); PyModule_AddIntConstant (gdb_module, "STDERR", 1); PyModule_AddIntConstant (gdb_module, "STDLOG", 2); - - /* gdb.parameter ("data-directory") doesn't necessarily exist when the python - script below is run (depending on order of _initialize_* functions). - Define the initial value of gdb.PYTHONDIR here. */ - { - char *gdb_pythondir; - - gdb_pythondir = concat (gdb_datadir, SLASH_STRING, "python", NULL); - PyModule_AddStringConstant (gdb_module, "PYTHONDIR", gdb_pythondir); - xfree (gdb_pythondir); - } gdbpy_gdb_error = PyErr_NewException ("gdb.error", PyExc_RuntimeError, NULL); PyModule_AddObject (gdb_module, "error", gdbpy_gdb_error); @@ -1310,6 +1600,7 @@ message == an error message without a stack will be printed."), gdbpy_gdberror_exc = PyErr_NewException ("gdb.GdbError", NULL, NULL); PyModule_AddObject (gdb_module, "GdbError", gdbpy_gdberror_exc); + gdbpy_initialize_gdb_readline (); gdbpy_initialize_auto_load (); gdbpy_initialize_values (); gdbpy_initialize_frames (); @@ -1339,12 +1630,10 @@ message == an error message without a stack will be printed."), gdbpy_initialize_exited_event (); gdbpy_initialize_thread_event (); gdbpy_initialize_new_objfile_event () ; + gdbpy_initialize_arch (); observer_attach_before_prompt (before_prompt_hook); - PyRun_SimpleString ("import gdb"); - PyRun_SimpleString ("gdb.pretty_printers = []"); - gdbpy_to_string_cst = PyString_FromString ("to_string"); gdbpy_children_cst = PyString_FromString ("children"); gdbpy_display_hint_cst = PyString_FromString ("display_hint"); @@ -1356,6 +1645,7 @@ message == an error message without a stack will be printed."), PyThreadState_Swap (NULL); PyEval_ReleaseLock (); + make_final_cleanup (finalize_python, NULL); #endif /* HAVE_PYTHON */ } @@ -1369,86 +1659,82 @@ message == an error message without a stack will be printed."), void finish_python_initialization (void) { + PyObject *m; + char *gdb_pythondir; + PyObject *sys_path; struct cleanup *cleanup; cleanup = ensure_python_env (get_current_arch (), current_language); - PyRun_SimpleString ("\ -import os\n\ -import sys\n\ -\n\ -class GdbOutputFile:\n\ - def close(self):\n\ - # Do nothing.\n\ - return None\n\ -\n\ - def isatty(self):\n\ - return False\n\ -\n\ - def write(self, s):\n\ - gdb.write(s, stream=gdb.STDOUT)\n \ -\n\ - def writelines(self, iterable):\n\ - for line in iterable:\n\ - self.write(line)\n\ -\n\ - def flush(self):\n\ - gdb.flush()\n\ -\n\ -sys.stdout = GdbOutputFile()\n\ -\n\ -class GdbOutputErrorFile:\n\ - def close(self):\n\ - # Do nothing.\n\ - return None\n\ -\n\ - def isatty(self):\n\ - return False\n\ -\n\ - def write(self, s):\n\ - gdb.write(s, stream=gdb.STDERR)\n \ -\n\ - def writelines(self, iterable):\n\ - for line in iterable:\n\ - self.write(line)\n \ -\n\ - def flush(self):\n\ - gdb.flush()\n\ -\n\ -sys.stderr = GdbOutputErrorFile()\n\ -\n\ -# Ideally this would live in the gdb module, but it's intentionally written\n\ -# in python, and we need this to bootstrap the gdb module.\n\ -\n\ -def GdbSetPythonDirectory (dir):\n\ - \"Set gdb.PYTHONDIR and update sys.path,etc.\"\n\ - old_dir = gdb.PYTHONDIR\n\ - gdb.PYTHONDIR = dir\n\ - # GDB's python scripts are stored inside gdb.PYTHONDIR. So insert\n\ - # that directory name at the start of sys.path to allow the Python\n\ - # interpreter to find them.\n\ - if old_dir in sys.path:\n\ - sys.path.remove (old_dir)\n\ - sys.path.insert (0, gdb.PYTHONDIR)\n\ -\n\ - # Tell python where to find submodules of gdb.\n\ - gdb.__path__ = [os.path.join (gdb.PYTHONDIR, 'gdb')]\n\ -\n\ - # The gdb module is implemented in C rather than in Python. As a result,\n\ - # the associated __init.py__ script is not not executed by default when\n\ - # the gdb module gets imported. Execute that script manually if it\n\ - # exists.\n\ - ipy = os.path.join (gdb.PYTHONDIR, 'gdb', '__init__.py')\n\ - if os.path.exists (ipy):\n\ - execfile (ipy)\n\ -\n\ -# Install the default gdb.PYTHONDIR.\n\ -GdbSetPythonDirectory (gdb.PYTHONDIR)\n\ -# Default prompt hook does nothing.\n\ -prompt_hook = None\n\ -"); + /* Add the initial data-directory to sys.path. */ + + gdb_pythondir = concat (gdb_datadir, SLASH_STRING, "python", NULL); + make_cleanup (xfree, gdb_pythondir); + + sys_path = PySys_GetObject ("path"); + + /* If sys.path is not defined yet, define it first. */ + if (!(sys_path && PyList_Check (sys_path))) + { +#ifdef IS_PY3K + PySys_SetPath (L""); +#else + PySys_SetPath (""); +#endif + sys_path = PySys_GetObject ("path"); + } + if (sys_path && PyList_Check (sys_path)) + { + PyObject *pythondir; + int err; + + pythondir = PyString_FromString (gdb_pythondir); + if (pythondir == NULL) + goto fail; + + err = PyList_Insert (sys_path, 0, pythondir); + if (err) + goto fail; + + Py_DECREF (pythondir); + } + else + goto fail; + + /* Import the gdb module to finish the initialization, and + add it to __main__ for convenience. */ + m = PyImport_AddModule ("__main__"); + if (m == NULL) + goto fail; + + gdb_python_module = PyImport_ImportModule ("gdb"); + if (gdb_python_module == NULL) + { + gdbpy_print_stack (); + /* This is passed in one call to warning so that blank lines aren't + inserted between each line of text. */ + warning (_("\n" + "Could not load the Python gdb module from `%s'.\n" + "Limited Python support is available from the _gdb module.\n" + "Suggest passing --data-directory=/path/to/gdb/data-directory.\n"), + gdb_pythondir); + do_cleanups (cleanup); + return; + } + + if (PyModule_AddObject (m, "gdb", gdb_python_module)) + goto fail; + + /* Keep the reference to gdb_python_module since it is in a global + variable. */ do_cleanups (cleanup); + return; + + fail: + gdbpy_print_stack (); + warning (_("internal error: Unhandled Python exception")); + do_cleanups (cleanup); } #endif /* HAVE_PYTHON */ @@ -1522,6 +1808,9 @@ gdb.Symtab_and_line objects (or None)."}, "parse_and_eval (String) -> Value.\n\ Parse String as an expression, evaluate it, and return the result as a Value." }, + { "find_pc_line", gdbpy_find_pc_line, METH_VARARGS, + "find_pc_line (pc) -> Symtab_and_line.\n\ +Return the gdb.Symtab_and_line object corresponding to the pc value." }, { "post_event", gdbpy_post_event, METH_VARARGS, "Post an event into gdb's event loop." }, @@ -1554,4 +1843,18 @@ Return a tuple containing all inferiors." }, {NULL, NULL, 0, NULL} }; +#ifdef IS_PY3K +static struct PyModuleDef GdbModuleDef = +{ + PyModuleDef_HEAD_INIT, + "_gdb", + NULL, + -1, + GdbMethods, + NULL, + NULL, + NULL, + NULL +}; +#endif #endif /* HAVE_PYTHON */ diff --git a/contrib/gdb-7/gdb/python/python.h b/contrib/gdb-7/gdb/python/python.h index 9e461f7ee9..24e3077a00 100644 --- a/contrib/gdb-7/gdb/python/python.h +++ b/contrib/gdb-7/gdb/python/python.h @@ -1,6 +1,6 @@ /* Python/gdb header for generic use in gdb - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -24,13 +24,15 @@ struct breakpoint_object; -extern int gdbpy_global_auto_load; +/* The suffix of per-objfile scripts to auto-load. + E.g. When the program loads libfoo.so, look for libfoo-gdb.py. */ +#define GDBPY_AUTO_FILE_NAME "-gdb.py" extern void finish_python_initialization (void); void eval_python_from_control_command (struct command_line *); -void source_python_script (const char *file); +void source_python_script (FILE *file, const char *filename); int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR address, @@ -41,10 +43,16 @@ int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, void preserve_python_values (struct objfile *objfile, htab_t copied_types); -void load_auto_scripts_for_objfile (struct objfile *objfile); +void gdbpy_load_auto_scripts_for_objfile (struct objfile *objfile); int gdbpy_should_stop (struct breakpoint_object *bp_obj); int gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj); +void *start_type_printers (void); + +char *apply_type_printers (void *, struct type *type); + +void free_type_printers (void *arg); + #endif /* GDB_PYTHON_H */ diff --git a/contrib/gdb-7/gdb/ravenscar-thread.c b/contrib/gdb-7/gdb/ravenscar-thread.c index 63ecad5440..ae01760b93 100644 --- a/contrib/gdb-7/gdb/ravenscar-thread.c +++ b/contrib/gdb-7/gdb/ravenscar-thread.c @@ -1,6 +1,6 @@ /* Ada Ravenscar thread support. - Copyright 2004, 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -34,10 +34,6 @@ /* If non-null, ravenscar task support is enabled. */ static int ravenscar_task_support = 1; -/* Non-null if the ravenscar thread layer has been pushed on the target - stack. */ -static int ravenscar_is_open = 0; - /* This module's target-specific operations. */ static struct target_ops ravenscar_ops; @@ -58,9 +54,6 @@ static const char ravenscar_runtime_initializer[] = static struct observer *update_target_observer = NULL; -/* Architecture-specific hooks. */ -static struct ravenscar_arch_ops* current_arch_ops; - static void ravenscar_find_new_threads (struct target_ops *ops); static ptid_t ravenscar_running_thread (void); static char *ravenscar_extra_thread_info (struct thread_info *tp); @@ -70,9 +63,8 @@ static void ravenscar_fetch_registers (struct target_ops *ops, static void ravenscar_store_registers (struct target_ops *ops, struct regcache *regcache, int regnum); static void ravenscar_prepare_to_store (struct regcache *regcache); -static void ravenscar_initialize (char *name, int from_tty); static void ravenscar_resume (struct target_ops *ops, ptid_t ptid, int step, - enum target_signal siggnal); + enum gdb_signal siggnal); static void ravenscar_mourn_inferior (struct target_ops *ops); static void ravenscar_update_inferior_ptid (void); static int has_ravenscar_runtime (void); @@ -166,7 +158,7 @@ get_running_thread_id (void) char *buf; CORE_ADDR object_addr; struct type *builtin_type_void_data_ptr = - builtin_type (target_gdbarch)->builtin_data_ptr; + builtin_type (target_gdbarch ())->builtin_data_ptr; if (!object_msym) return 0; @@ -179,15 +171,9 @@ get_running_thread_id (void) return extract_typed_address (buf, builtin_type_void_data_ptr); } -static void -ravenscar_close (int quitting) -{ - ravenscar_is_open = 0; -} - static void ravenscar_resume (struct target_ops *ops, ptid_t ptid, int step, - enum target_signal siggnal) + enum gdb_signal siggnal) { struct target_ops *beneath = find_target_beneath (ops); @@ -204,8 +190,19 @@ ravenscar_wait (struct target_ops *ops, ptid_t ptid, inferior_ptid = base_ptid; beneath->to_wait (beneath, base_ptid, status, 0); - ravenscar_find_new_threads (ops); - ravenscar_update_inferior_ptid (); + /* Find any new threads that might have been created, and update + inferior_ptid to the active thread. + + Only do it if the program is still alive, though. Otherwise, + this causes problems when debugging through the remote protocol, + because we might try switching threads (and thus sending packets) + after the remote has disconnected. */ + if (status->kind != TARGET_WAITKIND_EXITED + && status->kind != TARGET_WAITKIND_SIGNALLED) + { + ravenscar_find_new_threads (ops); + ravenscar_update_inferior_ptid (); + } return inferior_ptid; } @@ -276,7 +273,13 @@ ravenscar_fetch_registers (struct target_ops *ops, || ptid_equal (inferior_ptid, ravenscar_running_thread ())) beneath->to_fetch_registers (beneath, regcache, regnum); else - current_arch_ops->to_fetch_registers (regcache, regnum); + { + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct ravenscar_arch_ops *arch_ops + = gdbarch_ravenscar_ops (gdbarch); + + arch_ops->to_fetch_registers (regcache, regnum); + } } static void @@ -290,7 +293,13 @@ ravenscar_store_registers (struct target_ops *ops, || ptid_equal (inferior_ptid, ravenscar_running_thread ())) beneath->to_store_registers (beneath, regcache, regnum); else - current_arch_ops->to_store_registers (regcache, regnum); + { + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct ravenscar_arch_ops *arch_ops + = gdbarch_ravenscar_ops (gdbarch); + + arch_ops->to_store_registers (regcache, regnum); + } } static void @@ -303,7 +312,13 @@ ravenscar_prepare_to_store (struct regcache *regcache) || ptid_equal (inferior_ptid, ravenscar_running_thread ())) beneath->to_prepare_to_store (regcache); else - current_arch_ops->to_prepare_to_store (regcache); + { + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct ravenscar_arch_ops *arch_ops + = gdbarch_ravenscar_ops (gdbarch); + + arch_ops->to_prepare_to_store (regcache); + } } static void @@ -321,34 +336,16 @@ ravenscar_mourn_inferior (struct target_ops *ops) static void ravenscar_inferior_created (struct target_ops *target, int from_tty) { - if (ravenscar_task_support - && has_ravenscar_runtime ()) - ravenscar_initialize (NULL, 0); -} - -void -ravenscar_register_arch_ops (struct ravenscar_arch_ops *ops) -{ - /* FIXME: To be clean, we would need to handle a list of - architectures, just like in remote-wtx-hw.c. However, for now the - only Ravenscar run-time for bare board that is implemented in - GNAT is for only one architecture: erc32-elf. So no need to care about - that for now... */ - current_arch_ops = ops; -} + struct ravenscar_arch_ops *ops; -/* Initialize Ravenscar support. */ - -static void -ravenscar_initialize (char *name, int from_tty) -{ - if (ravenscar_is_open) + if (!ravenscar_task_support + || gdbarch_ravenscar_ops (current_inferior ()->gdbarch) == NULL + || !has_ravenscar_runtime ()) return; base_magic_null_ptid = inferior_ptid; ravenscar_update_inferior_ptid (); push_target (&ravenscar_ops); - ravenscar_is_open = 1; } static ptid_t @@ -363,7 +360,6 @@ init_ravenscar_thread_ops (void) ravenscar_ops.to_shortname = "ravenscar"; ravenscar_ops.to_longname = "Ravenscar tasks."; ravenscar_ops.to_doc = "Ravenscar tasks support."; - ravenscar_ops.to_close = ravenscar_close; ravenscar_ops.to_resume = ravenscar_resume; ravenscar_ops.to_wait = ravenscar_wait; ravenscar_ops.to_fetch_registers = ravenscar_fetch_registers; @@ -421,6 +417,9 @@ Support for Ravenscar task/thread switching is enabled\n")); Support for Ravenscar task/thread switching is disabled\n")); } +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern void _initialize_ravenscar (void); + /* Module startup initialization function, automagically called by init.c. */ diff --git a/contrib/gdb-7/gdb/ravenscar-thread.h b/contrib/gdb-7/gdb/ravenscar-thread.h index 5eeab38b61..3500caf80b 100644 --- a/contrib/gdb-7/gdb/ravenscar-thread.h +++ b/contrib/gdb-7/gdb/ravenscar-thread.h @@ -1,6 +1,6 @@ /* Ada Ravenscar thread support. - Copyright 2004, 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -29,13 +29,4 @@ struct ravenscar_arch_ops void (*to_prepare_to_store) (struct regcache *); }; -/* Register implementations for target ops to_store_registers, - to_prepare_to_store and to_fetch_registers when the inferior_ptid - is different from the running thread. In that case, the registers - are saved in a architecture-specific location. */ -/* FIXME: only one architecture can be registered for now. See - implementation. */ - -extern void ravenscar_register_arch_ops (struct ravenscar_arch_ops *ops); - #endif /* !defined (RAVENSCAR_THREAD_H) */ diff --git a/contrib/gdb-7/gdb/record-btrace.c b/contrib/gdb-7/gdb/record-btrace.c new file mode 100644 index 0000000000..b875ed1dc7 --- /dev/null +++ b/contrib/gdb-7/gdb/record-btrace.c @@ -0,0 +1,696 @@ +/* Branch trace support for GDB, the GNU debugger. + + Copyright (C) 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + 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 "record.h" +#include "gdbthread.h" +#include "target.h" +#include "gdbcmd.h" +#include "disasm.h" +#include "observer.h" +#include "exceptions.h" +#include "cli/cli-utils.h" +#include "source.h" +#include "ui-out.h" +#include "symtab.h" +#include "filenames.h" + +/* The target_ops of record-btrace. */ +static struct target_ops record_btrace_ops; + +/* A new thread observer enabling branch tracing for the new thread. */ +static struct observer *record_btrace_thread_observer; + +/* Print a record-btrace debug message. Use do ... while (0) to avoid + ambiguities when used in if statements. */ + +#define DEBUG(msg, args...) \ + do \ + { \ + if (record_debug != 0) \ + fprintf_unfiltered (gdb_stdlog, \ + "[record-btrace] " msg "\n", ##args); \ + } \ + while (0) + + +/* Update the branch trace for the current thread and return a pointer to its + branch trace information struct. + + Throws an error if there is no thread or no trace. This function never + returns NULL. */ + +static struct btrace_thread_info * +require_btrace (void) +{ + struct thread_info *tp; + struct btrace_thread_info *btinfo; + + DEBUG ("require"); + + tp = find_thread_ptid (inferior_ptid); + if (tp == NULL) + error (_("No thread.")); + + btrace_fetch (tp); + + btinfo = &tp->btrace; + + if (VEC_empty (btrace_inst_s, btinfo->itrace)) + error (_("No trace.")); + + return btinfo; +} + +/* Enable branch tracing for one thread. Warn on errors. */ + +static void +record_btrace_enable_warn (struct thread_info *tp) +{ + volatile struct gdb_exception error; + + TRY_CATCH (error, RETURN_MASK_ERROR) + btrace_enable (tp); + + if (error.message != NULL) + warning ("%s", error.message); +} + +/* Callback function to disable branch tracing for one thread. */ + +static void +record_btrace_disable_callback (void *arg) +{ + struct thread_info *tp; + + tp = arg; + + btrace_disable (tp); +} + +/* Enable automatic tracing of new threads. */ + +static void +record_btrace_auto_enable (void) +{ + DEBUG ("attach thread observer"); + + record_btrace_thread_observer + = observer_attach_new_thread (record_btrace_enable_warn); +} + +/* Disable automatic tracing of new threads. */ + +static void +record_btrace_auto_disable (void) +{ + /* The observer may have been detached, already. */ + if (record_btrace_thread_observer == NULL) + return; + + DEBUG ("detach thread observer"); + + observer_detach_new_thread (record_btrace_thread_observer); + record_btrace_thread_observer = NULL; +} + +/* The to_open method of target record-btrace. */ + +static void +record_btrace_open (char *args, int from_tty) +{ + struct cleanup *disable_chain; + struct thread_info *tp; + + DEBUG ("open"); + + if (RECORD_IS_USED) + error (_("The process is already being recorded.")); + + if (!target_has_execution) + error (_("The program is not being run.")); + + if (!target_supports_btrace ()) + error (_("Target does not support branch tracing.")); + + gdb_assert (record_btrace_thread_observer == NULL); + + disable_chain = make_cleanup (null_cleanup, NULL); + ALL_THREADS (tp) + if (args == NULL || *args == 0 || number_is_in_list (args, tp->num)) + { + btrace_enable (tp); + + make_cleanup (record_btrace_disable_callback, tp); + } + + record_btrace_auto_enable (); + + push_target (&record_btrace_ops); + + observer_notify_record_changed (current_inferior (), 1); + + discard_cleanups (disable_chain); +} + +/* The to_stop_recording method of target record-btrace. */ + +static void +record_btrace_stop_recording (void) +{ + struct thread_info *tp; + + DEBUG ("stop recording"); + + record_btrace_auto_disable (); + + ALL_THREADS (tp) + if (tp->btrace.target != NULL) + btrace_disable (tp); +} + +/* The to_close method of target record-btrace. */ + +static void +record_btrace_close (int quitting) +{ + /* Make sure automatic recording gets disabled even if we did not stop + recording before closing the record-btrace target. */ + record_btrace_auto_disable (); + + /* We already stopped recording. */ +} + +/* The to_info_record method of target record-btrace. */ + +static void +record_btrace_info (void) +{ + struct btrace_thread_info *btinfo; + struct thread_info *tp; + unsigned int insts, funcs; + + DEBUG ("info"); + + tp = find_thread_ptid (inferior_ptid); + if (tp == NULL) + error (_("No thread.")); + + btrace_fetch (tp); + + btinfo = &tp->btrace; + insts = VEC_length (btrace_inst_s, btinfo->itrace); + funcs = VEC_length (btrace_func_s, btinfo->ftrace); + + printf_unfiltered (_("Recorded %u instructions in %u functions for thread " + "%d (%s).\n"), insts, funcs, tp->num, + target_pid_to_str (tp->ptid)); +} + +/* Print an unsigned int. */ + +static void +ui_out_field_uint (struct ui_out *uiout, const char *fld, unsigned int val) +{ + ui_out_field_fmt (uiout, fld, "%u", val); +} + +/* Disassemble a section of the recorded instruction trace. */ + +static void +btrace_insn_history (struct btrace_thread_info *btinfo, struct ui_out *uiout, + unsigned int begin, unsigned int end, int flags) +{ + struct gdbarch *gdbarch; + struct btrace_inst *inst; + unsigned int idx; + + DEBUG ("itrace (0x%x): [%u; %u[", flags, begin, end); + + gdbarch = target_gdbarch (); + + for (idx = begin; VEC_iterate (btrace_inst_s, btinfo->itrace, idx, inst) + && idx < end; ++idx) + { + /* Print the instruction index. */ + ui_out_field_uint (uiout, "index", idx); + ui_out_text (uiout, "\t"); + + /* Disassembly with '/m' flag may not produce the expected result. + See PR gdb/11833. */ + gdb_disassembly (gdbarch, uiout, NULL, flags, 1, inst->pc, inst->pc + 1); + } +} + +/* The to_insn_history method of target record-btrace. */ + +static void +record_btrace_insn_history (int size, int flags) +{ + struct btrace_thread_info *btinfo; + struct cleanup *uiout_cleanup; + struct ui_out *uiout; + unsigned int context, last, begin, end; + + uiout = current_uiout; + uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, + "insn history"); + btinfo = require_btrace (); + last = VEC_length (btrace_inst_s, btinfo->itrace); + + context = abs (size); + begin = btinfo->insn_iterator.begin; + end = btinfo->insn_iterator.end; + + DEBUG ("insn-history (0x%x): %d, prev: [%u; %u[", flags, size, begin, end); + + if (context == 0) + error (_("Bad record instruction-history-size.")); + + /* We start at the end. */ + if (end < begin) + { + /* Truncate the context, if necessary. */ + context = min (context, last); + + end = last; + begin = end - context; + } + else if (size < 0) + { + if (begin == 0) + { + printf_unfiltered (_("At the start of the branch trace record.\n")); + + btinfo->insn_iterator.end = 0; + return; + } + + /* Truncate the context, if necessary. */ + context = min (context, begin); + + end = begin; + begin -= context; + } + else + { + if (end == last) + { + printf_unfiltered (_("At the end of the branch trace record.\n")); + + btinfo->insn_iterator.begin = last; + return; + } + + /* Truncate the context, if necessary. */ + context = min (context, last - end); + + begin = end; + end += context; + } + + btrace_insn_history (btinfo, uiout, begin, end, flags); + + btinfo->insn_iterator.begin = begin; + btinfo->insn_iterator.end = end; + + do_cleanups (uiout_cleanup); +} + +/* The to_insn_history_range method of target record-btrace. */ + +static void +record_btrace_insn_history_range (ULONGEST from, ULONGEST to, int flags) +{ + struct btrace_thread_info *btinfo; + struct cleanup *uiout_cleanup; + struct ui_out *uiout; + unsigned int last, begin, end; + + uiout = current_uiout; + uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, + "insn history"); + btinfo = require_btrace (); + last = VEC_length (btrace_inst_s, btinfo->itrace); + + begin = (unsigned int) from; + end = (unsigned int) to; + + DEBUG ("insn-history (0x%x): [%u; %u[", flags, begin, end); + + /* Check for wrap-arounds. */ + if (begin != from || end != to) + error (_("Bad range.")); + + if (end <= begin) + error (_("Bad range.")); + + if (last <= begin) + error (_("Range out of bounds.")); + + /* Truncate the range, if necessary. */ + if (last < end) + end = last; + + btrace_insn_history (btinfo, uiout, begin, end, flags); + + btinfo->insn_iterator.begin = begin; + btinfo->insn_iterator.end = end; + + do_cleanups (uiout_cleanup); +} + +/* The to_insn_history_from method of target record-btrace. */ + +static void +record_btrace_insn_history_from (ULONGEST from, int size, int flags) +{ + ULONGEST begin, end, context; + + context = abs (size); + + if (size < 0) + { + end = from; + + if (from < context) + begin = 0; + else + begin = from - context; + } + else + { + begin = from; + end = from + context; + + /* Check for wrap-around. */ + if (end < begin) + end = ULONGEST_MAX; + } + + record_btrace_insn_history_range (begin, end, flags); +} + +/* Print the instruction number range for a function call history line. */ + +static void +btrace_func_history_insn_range (struct ui_out *uiout, struct btrace_func *bfun) +{ + ui_out_field_uint (uiout, "insn begin", bfun->ibegin); + + if (bfun->ibegin == bfun->iend) + return; + + ui_out_text (uiout, "-"); + ui_out_field_uint (uiout, "insn end", bfun->iend); +} + +/* Print the source line information for a function call history line. */ + +static void +btrace_func_history_src_line (struct ui_out *uiout, struct btrace_func *bfun) +{ + struct symbol *sym; + + sym = bfun->sym; + if (sym == NULL) + return; + + ui_out_field_string (uiout, "file", + symtab_to_filename_for_display (sym->symtab)); + + if (bfun->lend == 0) + return; + + ui_out_text (uiout, ":"); + ui_out_field_int (uiout, "min line", bfun->lbegin); + + if (bfun->lend == bfun->lbegin) + return; + + ui_out_text (uiout, "-"); + ui_out_field_int (uiout, "max line", bfun->lend); +} + +/* Disassemble a section of the recorded function trace. */ + +static void +btrace_func_history (struct btrace_thread_info *btinfo, struct ui_out *uiout, + unsigned int begin, unsigned int end, + enum record_print_flag flags) +{ + struct btrace_func *bfun; + unsigned int idx; + + DEBUG ("ftrace (0x%x): [%u; %u[", flags, begin, end); + + for (idx = begin; VEC_iterate (btrace_func_s, btinfo->ftrace, idx, bfun) + && idx < end; ++idx) + { + /* Print the function index. */ + ui_out_field_uint (uiout, "index", idx); + ui_out_text (uiout, "\t"); + + if ((flags & record_print_insn_range) != 0) + { + btrace_func_history_insn_range (uiout, bfun); + ui_out_text (uiout, "\t"); + } + + if ((flags & record_print_src_line) != 0) + { + btrace_func_history_src_line (uiout, bfun); + ui_out_text (uiout, "\t"); + } + + if (bfun->sym != NULL) + ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (bfun->sym)); + else if (bfun->msym != NULL) + ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (bfun->msym)); + ui_out_text (uiout, "\n"); + } +} + +/* The to_call_history method of target record-btrace. */ + +static void +record_btrace_call_history (int size, int flags) +{ + struct btrace_thread_info *btinfo; + struct cleanup *uiout_cleanup; + struct ui_out *uiout; + unsigned int context, last, begin, end; + + uiout = current_uiout; + uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, + "insn history"); + btinfo = require_btrace (); + last = VEC_length (btrace_func_s, btinfo->ftrace); + + context = abs (size); + begin = btinfo->func_iterator.begin; + end = btinfo->func_iterator.end; + + DEBUG ("func-history (0x%x): %d, prev: [%u; %u[", flags, size, begin, end); + + if (context == 0) + error (_("Bad record function-call-history-size.")); + + /* We start at the end. */ + if (end < begin) + { + /* Truncate the context, if necessary. */ + context = min (context, last); + + end = last; + begin = end - context; + } + else if (size < 0) + { + if (begin == 0) + { + printf_unfiltered (_("At the start of the branch trace record.\n")); + + btinfo->func_iterator.end = 0; + return; + } + + /* Truncate the context, if necessary. */ + context = min (context, begin); + + end = begin; + begin -= context; + } + else + { + if (end == last) + { + printf_unfiltered (_("At the end of the branch trace record.\n")); + + btinfo->func_iterator.begin = last; + return; + } + + /* Truncate the context, if necessary. */ + context = min (context, last - end); + + begin = end; + end += context; + } + + btrace_func_history (btinfo, uiout, begin, end, flags); + + btinfo->func_iterator.begin = begin; + btinfo->func_iterator.end = end; + + do_cleanups (uiout_cleanup); +} + +/* The to_call_history_range method of target record-btrace. */ + +static void +record_btrace_call_history_range (ULONGEST from, ULONGEST to, int flags) +{ + struct btrace_thread_info *btinfo; + struct cleanup *uiout_cleanup; + struct ui_out *uiout; + unsigned int last, begin, end; + + uiout = current_uiout; + uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, + "func history"); + btinfo = require_btrace (); + last = VEC_length (btrace_func_s, btinfo->ftrace); + + begin = (unsigned int) from; + end = (unsigned int) to; + + DEBUG ("func-history (0x%x): [%u; %u[", flags, begin, end); + + /* Check for wrap-arounds. */ + if (begin != from || end != to) + error (_("Bad range.")); + + if (end <= begin) + error (_("Bad range.")); + + if (last <= begin) + error (_("Range out of bounds.")); + + /* Truncate the range, if necessary. */ + if (last < end) + end = last; + + btrace_func_history (btinfo, uiout, begin, end, flags); + + btinfo->func_iterator.begin = begin; + btinfo->func_iterator.end = end; + + do_cleanups (uiout_cleanup); +} + +/* The to_call_history_from method of target record-btrace. */ + +static void +record_btrace_call_history_from (ULONGEST from, int size, int flags) +{ + ULONGEST begin, end, context; + + context = abs (size); + + if (size < 0) + { + end = from; + + if (from < context) + begin = 0; + else + begin = from - context; + } + else + { + begin = from; + end = from + context; + + /* Check for wrap-around. */ + if (end < begin) + end = ULONGEST_MAX; + } + + record_btrace_call_history_range (begin, end, flags); +} + +/* Initialize the record-btrace target ops. */ + +static void +init_record_btrace_ops (void) +{ + struct target_ops *ops; + + ops = &record_btrace_ops; + ops->to_shortname = "record-btrace"; + ops->to_longname = "Branch tracing target"; + ops->to_doc = "Collect control-flow trace and provide the execution history."; + ops->to_open = record_btrace_open; + ops->to_close = record_btrace_close; + ops->to_detach = record_detach; + ops->to_disconnect = record_disconnect; + ops->to_mourn_inferior = record_mourn_inferior; + ops->to_kill = record_kill; + ops->to_create_inferior = find_default_create_inferior; + ops->to_stop_recording = record_btrace_stop_recording; + ops->to_info_record = record_btrace_info; + ops->to_insn_history = record_btrace_insn_history; + ops->to_insn_history_from = record_btrace_insn_history_from; + ops->to_insn_history_range = record_btrace_insn_history_range; + ops->to_call_history = record_btrace_call_history; + ops->to_call_history_from = record_btrace_call_history_from; + ops->to_call_history_range = record_btrace_call_history_range; + ops->to_stratum = record_stratum; + ops->to_magic = OPS_MAGIC; +} + +/* Alias for "target record". */ + +static void +cmd_record_btrace_start (char *args, int from_tty) +{ + if (args != NULL && *args != 0) + error (_("Invalid argument.")); + + execute_command ("target record-btrace", from_tty); +} + +void _initialize_record_btrace (void); + +/* Initialize btrace commands. */ + +void +_initialize_record_btrace (void) +{ + add_cmd ("btrace", class_obscure, cmd_record_btrace_start, + _("Start branch trace recording."), + &record_cmdlist); + add_alias_cmd ("b", "btrace", class_obscure, 1, &record_cmdlist); + + init_record_btrace_ops (); + add_target (&record_btrace_ops); +} diff --git a/contrib/gdb-7/gdb/record.c b/contrib/gdb-7/gdb/record-full.c similarity index 51% copy from contrib/gdb-7/gdb/record.c copy to contrib/gdb-7/gdb/record-full.c index e396262a52..e7af504d5a 100644 --- a/contrib/gdb-7/gdb/record.c +++ b/contrib/gdb-7/gdb/record-full.c @@ -1,6 +1,6 @@ /* Process record and replay target for GDB, the GNU debugger. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2013 Free Software Foundation, Inc. This file is part of GDB. @@ -28,14 +28,17 @@ #include "gdbcore.h" #include "exec.h" #include "record.h" +#include "record-full.h" #include "elf-bfd.h" #include "gcore.h" #include "event-loop.h" #include "inf-loop.h" +#include "gdb_bfd.h" +#include "observer.h" #include -/* This module implements "target record", also known as "process +/* This module implements "target record-full", also known as "process record and replay". This target sits on top of a "normal" target (a target that "has execution"), and provides a record and replay functionality, including reverse debugging. @@ -55,25 +58,25 @@ instruction's side effects by duplicating the changes that it would have made on memory and registers. */ -#define DEFAULT_RECORD_INSN_MAX_NUM 200000 +#define DEFAULT_RECORD_FULL_INSN_MAX_NUM 200000 -#define RECORD_IS_REPLAY \ - (record_list->next || execution_direction == EXEC_REVERSE) +#define RECORD_FULL_IS_REPLAY \ + (record_full_list->next || execution_direction == EXEC_REVERSE) -#define RECORD_FILE_MAGIC netorder32(0x20091016) +#define RECORD_FULL_FILE_MAGIC netorder32(0x20091016) /* These are the core structs of the process record functionality. - A record_entry is a record of the value change of a register - ("record_reg") or a part of memory ("record_mem"). And each - instruction must have a struct record_entry ("record_end") that - indicates that this is the last struct record_entry of this + A record_full_entry is a record of the value change of a register + ("record_full_reg") or a part of memory ("record_full_mem"). And each + instruction must have a struct record_full_entry ("record_full_end") + that indicates that this is the last struct record_full_entry of this instruction. - Each struct record_entry is linked to "record_list" by "prev" and - "next" pointers. */ + Each struct record_full_entry is linked to "record_full_list" by "prev" + and "next" pointers. */ -struct record_mem_entry +struct record_full_mem_entry { CORE_ADDR addr; int len; @@ -87,7 +90,7 @@ struct record_mem_entry } u; }; -struct record_reg_entry +struct record_full_reg_entry { unsigned short num; unsigned short len; @@ -98,33 +101,33 @@ struct record_reg_entry } u; }; -struct record_end_entry +struct record_full_end_entry { - enum target_signal sigval; + enum gdb_signal sigval; ULONGEST insn_num; }; -enum record_type +enum record_full_type { - record_end = 0, - record_reg, - record_mem + record_full_end = 0, + record_full_reg, + record_full_mem }; /* This is the data structure that makes up the execution log. The execution log consists of a single linked list of entries - of type "struct record_entry". It is doubly linked so that it + of type "struct record_full_entry". It is doubly linked so that it can be traversed in either direction. The start of the list is anchored by a struct called - "record_first". The pointer "record_list" either points to the - last entry that was added to the list (in record mode), or to the - next entry in the list that will be executed (in replay mode). + "record_full_first". The pointer "record_full_list" either points + to the last entry that was added to the list (in record mode), or to + the next entry in the list that will be executed (in replay mode). - Each list element (struct record_entry), in addition to next and - prev pointers, consists of a union of three entry types: mem, reg, - and end. A field called "type" determines which entry type is + Each list element (struct record_full_entry), in addition to next + and prev pointers, consists of a union of three entry types: mem, + reg, and end. A field called "type" determines which entry type is represented by a given list element. Each instruction that is added to the execution log is represented @@ -135,119 +138,134 @@ enum record_type each instruction will have an "end" entry that separates it from the changes associated with the next instruction. */ -struct record_entry +struct record_full_entry { - struct record_entry *prev; - struct record_entry *next; - enum record_type type; + struct record_full_entry *prev; + struct record_full_entry *next; + enum record_full_type type; union { /* reg */ - struct record_reg_entry reg; + struct record_full_reg_entry reg; /* mem */ - struct record_mem_entry mem; + struct record_full_mem_entry mem; /* end */ - struct record_end_entry end; + struct record_full_end_entry end; } u; }; -/* This is the debug switch for process record. */ -int record_debug = 0; - /* If true, query if PREC cannot record memory change of next instruction. */ -int record_memory_query = 0; +int record_full_memory_query = 0; -struct record_core_buf_entry +struct record_full_core_buf_entry { - struct record_core_buf_entry *prev; + struct record_full_core_buf_entry *prev; struct target_section *p; bfd_byte *buf; }; /* Record buf with core target. */ -static gdb_byte *record_core_regbuf = NULL; -static struct target_section *record_core_start; -static struct target_section *record_core_end; -static struct record_core_buf_entry *record_core_buf_list = NULL; +static gdb_byte *record_full_core_regbuf = NULL; +static struct target_section *record_full_core_start; +static struct target_section *record_full_core_end; +static struct record_full_core_buf_entry *record_full_core_buf_list = NULL; /* The following variables are used for managing the linked list that represents the execution log. - record_first is the anchor that holds down the beginning of the list. + record_full_first is the anchor that holds down the beginning of + the list. - record_list serves two functions: + record_full_list serves two functions: 1) In record mode, it anchors the end of the list. 2) In replay mode, it traverses the list and points to the next instruction that must be emulated. - record_arch_list_head and record_arch_list_tail are used to manage - a separate list, which is used to build up the change elements of - the currently executing instruction during record mode. When this - instruction has been completely annotated in the "arch list", it - will be appended to the main execution log. */ + record_full_arch_list_head and record_full_arch_list_tail are used + to manage a separate list, which is used to build up the change + elements of the currently executing instruction during record mode. + When this instruction has been completely annotated in the "arch + list", it will be appended to the main execution log. */ -static struct record_entry record_first; -static struct record_entry *record_list = &record_first; -static struct record_entry *record_arch_list_head = NULL; -static struct record_entry *record_arch_list_tail = NULL; +static struct record_full_entry record_full_first; +static struct record_full_entry *record_full_list = &record_full_first; +static struct record_full_entry *record_full_arch_list_head = NULL; +static struct record_full_entry *record_full_arch_list_tail = NULL; -/* 1 ask user. 0 auto delete the last struct record_entry. */ -static int record_stop_at_limit = 1; +/* 1 ask user. 0 auto delete the last struct record_full_entry. */ +static int record_full_stop_at_limit = 1; /* Maximum allowed number of insns in execution log. */ -static unsigned int record_insn_max_num = DEFAULT_RECORD_INSN_MAX_NUM; +static unsigned int record_full_insn_max_num + = DEFAULT_RECORD_FULL_INSN_MAX_NUM; /* Actual count of insns presently in execution log. */ -static int record_insn_num = 0; +static int record_full_insn_num = 0; /* Count of insns logged so far (may be larger than count of insns presently in execution log). */ -static ULONGEST record_insn_count; +static ULONGEST record_full_insn_count; /* The target_ops of process record. */ -static struct target_ops record_ops; -static struct target_ops record_core_ops; +static struct target_ops record_full_ops; +static struct target_ops record_full_core_ops; + +/* Command lists for "set/show record full". */ +static struct cmd_list_element *set_record_full_cmdlist; +static struct cmd_list_element *show_record_full_cmdlist; + +/* Command list for "record full". */ +static struct cmd_list_element *record_full_cmdlist; /* The beneath function pointers. */ -static struct target_ops *record_beneath_to_resume_ops; -static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int, - enum target_signal); -static struct target_ops *record_beneath_to_wait_ops; -static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t, - struct target_waitstatus *, - int); -static struct target_ops *record_beneath_to_store_registers_ops; -static void (*record_beneath_to_store_registers) (struct target_ops *, - struct regcache *, - int regno); -static struct target_ops *record_beneath_to_xfer_partial_ops; -static LONGEST (*record_beneath_to_xfer_partial) (struct target_ops *ops, - enum target_object object, - const char *annex, - gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, - LONGEST len); -static int (*record_beneath_to_insert_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*record_beneath_to_stopped_by_watchpoint) (void); -static int (*record_beneath_to_stopped_data_address) (struct target_ops *, - CORE_ADDR *); -static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *); - -/* Alloc and free functions for record_reg, record_mem, and record_end - entries. */ - -/* Alloc a record_reg record entry. */ - -static inline struct record_entry * -record_reg_alloc (struct regcache *regcache, int regnum) -{ - struct record_entry *rec; +static struct target_ops *record_full_beneath_to_resume_ops; +static void (*record_full_beneath_to_resume) (struct target_ops *, ptid_t, int, + enum gdb_signal); +static struct target_ops *record_full_beneath_to_wait_ops; +static ptid_t (*record_full_beneath_to_wait) (struct target_ops *, ptid_t, + struct target_waitstatus *, + int); +static struct target_ops *record_full_beneath_to_store_registers_ops; +static void (*record_full_beneath_to_store_registers) (struct target_ops *, + struct regcache *, + int regno); +static struct target_ops *record_full_beneath_to_xfer_partial_ops; +static LONGEST + (*record_full_beneath_to_xfer_partial) (struct target_ops *ops, + enum target_object object, + const char *annex, + gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, + LONGEST len); +static int + (*record_full_beneath_to_insert_breakpoint) (struct gdbarch *, + struct bp_target_info *); +static int + (*record_full_beneath_to_remove_breakpoint) (struct gdbarch *, + struct bp_target_info *); +static int (*record_full_beneath_to_stopped_by_watchpoint) (void); +static int (*record_full_beneath_to_stopped_data_address) (struct target_ops *, + CORE_ADDR *); +static void + (*record_full_beneath_to_async) (void (*) (enum inferior_event_type, void *), + void *); + +static void record_full_goto_insn (struct record_full_entry *entry, + enum exec_direction_kind dir); +static void record_full_save (char *recfilename); + +/* Alloc and free functions for record_full_reg, record_full_mem, and + record_full_end entries. */ + +/* Alloc a record_full_reg record entry. */ + +static inline struct record_full_entry * +record_full_reg_alloc (struct regcache *regcache, int regnum) +{ + struct record_full_entry *rec; struct gdbarch *gdbarch = get_regcache_arch (regcache); - rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry)); - rec->type = record_reg; + rec = xcalloc (1, sizeof (struct record_full_entry)); + rec->type = record_full_reg; rec->u.reg.num = regnum; rec->u.reg.len = register_size (gdbarch, regnum); if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) @@ -256,26 +274,26 @@ record_reg_alloc (struct regcache *regcache, int regnum) return rec; } -/* Free a record_reg record entry. */ +/* Free a record_full_reg record entry. */ static inline void -record_reg_release (struct record_entry *rec) +record_full_reg_release (struct record_full_entry *rec) { - gdb_assert (rec->type == record_reg); + gdb_assert (rec->type == record_full_reg); if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) xfree (rec->u.reg.u.ptr); xfree (rec); } -/* Alloc a record_mem record entry. */ +/* Alloc a record_full_mem record entry. */ -static inline struct record_entry * -record_mem_alloc (CORE_ADDR addr, int len) +static inline struct record_full_entry * +record_full_mem_alloc (CORE_ADDR addr, int len) { - struct record_entry *rec; + struct record_full_entry *rec; - rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry)); - rec->type = record_mem; + rec = xcalloc (1, sizeof (struct record_full_entry)); + rec->type = record_full_mem; rec->u.mem.addr = addr; rec->u.mem.len = len; if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) @@ -284,34 +302,34 @@ record_mem_alloc (CORE_ADDR addr, int len) return rec; } -/* Free a record_mem record entry. */ +/* Free a record_full_mem record entry. */ static inline void -record_mem_release (struct record_entry *rec) +record_full_mem_release (struct record_full_entry *rec) { - gdb_assert (rec->type == record_mem); + gdb_assert (rec->type == record_full_mem); if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) xfree (rec->u.mem.u.ptr); xfree (rec); } -/* Alloc a record_end record entry. */ +/* Alloc a record_full_end record entry. */ -static inline struct record_entry * -record_end_alloc (void) +static inline struct record_full_entry * +record_full_end_alloc (void) { - struct record_entry *rec; + struct record_full_entry *rec; - rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry)); - rec->type = record_end; + rec = xcalloc (1, sizeof (struct record_full_entry)); + rec->type = record_full_end; return rec; } -/* Free a record_end record entry. */ +/* Free a record_full_end record entry. */ static inline void -record_end_release (struct record_entry *rec) +record_full_end_release (struct record_full_entry *rec) { xfree (rec); } @@ -319,20 +337,20 @@ record_end_release (struct record_entry *rec) /* Free one record entry, any type. Return entry->type, in case caller wants to know. */ -static inline enum record_type -record_entry_release (struct record_entry *rec) +static inline enum record_full_type +record_full_entry_release (struct record_full_entry *rec) { - enum record_type type = rec->type; + enum record_full_type type = rec->type; switch (type) { - case record_reg: - record_reg_release (rec); + case record_full_reg: + record_full_reg_release (rec); break; - case record_mem: - record_mem_release (rec); + case record_full_mem: + record_full_mem_release (rec); break; - case record_end: - record_end_release (rec); + case record_full_end: + record_full_end_release (rec); break; } return type; @@ -341,7 +359,7 @@ record_entry_release (struct record_entry *rec) /* Free all record entries in list pointed to by REC. */ static void -record_list_release (struct record_entry *rec) +record_full_list_release (struct record_full_entry *rec) { if (!rec) return; @@ -352,33 +370,33 @@ record_list_release (struct record_entry *rec) while (rec->prev) { rec = rec->prev; - record_entry_release (rec->next); + record_full_entry_release (rec->next); } - if (rec == &record_first) + if (rec == &record_full_first) { - record_insn_num = 0; - record_first.next = NULL; + record_full_insn_num = 0; + record_full_first.next = NULL; } else - record_entry_release (rec); + record_full_entry_release (rec); } /* Free all record entries forward of the given list position. */ static void -record_list_release_following (struct record_entry *rec) +record_full_list_release_following (struct record_full_entry *rec) { - struct record_entry *tmp = rec->next; + struct record_full_entry *tmp = rec->next; rec->next = NULL; while (tmp) { rec = tmp->next; - if (record_entry_release (tmp) == record_end) + if (record_full_entry_release (tmp) == record_full_end) { - record_insn_num--; - record_insn_count--; + record_full_insn_num--; + record_full_insn_count--; } tmp = rec; } @@ -387,87 +405,87 @@ record_list_release_following (struct record_entry *rec) /* Delete the first instruction from the beginning of the log, to make room for adding a new instruction at the end of the log. - Note -- this function does not modify record_insn_num. */ + Note -- this function does not modify record_full_insn_num. */ static void -record_list_release_first (void) +record_full_list_release_first (void) { - struct record_entry *tmp; + struct record_full_entry *tmp; - if (!record_first.next) + if (!record_full_first.next) return; - /* Loop until a record_end. */ + /* Loop until a record_full_end. */ while (1) { - /* Cut record_first.next out of the linked list. */ - tmp = record_first.next; - record_first.next = tmp->next; - tmp->next->prev = &record_first; + /* Cut record_full_first.next out of the linked list. */ + tmp = record_full_first.next; + record_full_first.next = tmp->next; + tmp->next->prev = &record_full_first; /* tmp is now isolated, and can be deleted. */ - if (record_entry_release (tmp) == record_end) - break; /* End loop at first record_end. */ + if (record_full_entry_release (tmp) == record_full_end) + break; /* End loop at first record_full_end. */ - if (!record_first.next) + if (!record_full_first.next) { - gdb_assert (record_insn_num == 1); + gdb_assert (record_full_insn_num == 1); break; /* End loop when list is empty. */ } } } -/* Add a struct record_entry to record_arch_list. */ +/* Add a struct record_full_entry to record_full_arch_list. */ static void -record_arch_list_add (struct record_entry *rec) +record_full_arch_list_add (struct record_full_entry *rec) { if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, - "Process record: record_arch_list_add %s.\n", + "Process record: record_full_arch_list_add %s.\n", host_address_to_string (rec)); - if (record_arch_list_tail) + if (record_full_arch_list_tail) { - record_arch_list_tail->next = rec; - rec->prev = record_arch_list_tail; - record_arch_list_tail = rec; + record_full_arch_list_tail->next = rec; + rec->prev = record_full_arch_list_tail; + record_full_arch_list_tail = rec; } else { - record_arch_list_head = rec; - record_arch_list_tail = rec; + record_full_arch_list_head = rec; + record_full_arch_list_tail = rec; } } /* Return the value storage location of a record entry. */ static inline gdb_byte * -record_get_loc (struct record_entry *rec) +record_full_get_loc (struct record_full_entry *rec) { switch (rec->type) { - case record_mem: + case record_full_mem: if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) return rec->u.mem.u.ptr; else return rec->u.mem.u.buf; - case record_reg: + case record_full_reg: if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) return rec->u.reg.u.ptr; else return rec->u.reg.u.buf; - case record_end: + case record_full_end: default: - gdb_assert_not_reached ("unexpected record_entry type"); + gdb_assert_not_reached ("unexpected record_full_entry type"); return NULL; } } -/* Record the value of a register NUM to record_arch_list. */ +/* Record the value of a register NUM to record_full_arch_list. */ int -record_arch_list_add_reg (struct regcache *regcache, int regnum) +record_full_arch_list_add_reg (struct regcache *regcache, int regnum) { - struct record_entry *rec; + struct record_full_entry *rec; if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, @@ -475,80 +493,77 @@ record_arch_list_add_reg (struct regcache *regcache, int regnum) "record list.\n", regnum); - rec = record_reg_alloc (regcache, regnum); + rec = record_full_reg_alloc (regcache, regnum); - regcache_raw_read (regcache, regnum, record_get_loc (rec)); + regcache_raw_read (regcache, regnum, record_full_get_loc (rec)); - record_arch_list_add (rec); + record_full_arch_list_add (rec); return 0; } /* Record the value of a region of memory whose address is ADDR and - length is LEN to record_arch_list. */ + length is LEN to record_full_arch_list. */ int -record_arch_list_add_mem (CORE_ADDR addr, int len) +record_full_arch_list_add_mem (CORE_ADDR addr, int len) { - struct record_entry *rec; + struct record_full_entry *rec; if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, "Process record: add mem addr = %s len = %d to " "record list.\n", - paddress (target_gdbarch, addr), len); + paddress (target_gdbarch (), addr), len); if (!addr) /* FIXME: Why? Some arch must permit it... */ return 0; - rec = record_mem_alloc (addr, len); + rec = record_full_mem_alloc (addr, len); - if (target_read_memory (addr, record_get_loc (rec), len)) + if (record_read_memory (target_gdbarch (), addr, + record_full_get_loc (rec), len)) { - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: error reading memory at " - "addr = %s len = %d.\n", - paddress (target_gdbarch, addr), len); - record_mem_release (rec); + record_full_mem_release (rec); return -1; } - record_arch_list_add (rec); + record_full_arch_list_add (rec); return 0; } -/* Add a record_end type struct record_entry to record_arch_list. */ +/* Add a record_full_end type struct record_full_entry to + record_full_arch_list. */ int -record_arch_list_add_end (void) +record_full_arch_list_add_end (void) { - struct record_entry *rec; + struct record_full_entry *rec; if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, "Process record: add end to arch list.\n"); - rec = record_end_alloc (); - rec->u.end.sigval = TARGET_SIGNAL_0; - rec->u.end.insn_num = ++record_insn_count; + rec = record_full_end_alloc (); + rec->u.end.sigval = GDB_SIGNAL_0; + rec->u.end.insn_num = ++record_full_insn_count; - record_arch_list_add (rec); + record_full_arch_list_add (rec); return 0; } static void -record_check_insn_num (int set_terminal) +record_full_check_insn_num (int set_terminal) { - if (record_insn_max_num) + if (record_full_insn_max_num) { - gdb_assert (record_insn_num <= record_insn_max_num); - if (record_insn_num == record_insn_max_num) + gdb_assert (record_full_insn_num <= record_full_insn_max_num); + if (record_full_insn_num == record_full_insn_max_num) { /* Ask user what to do. */ - if (record_stop_at_limit) + if (record_full_stop_at_limit) { int q; @@ -556,11 +571,11 @@ record_check_insn_num (int set_terminal) target_terminal_ours (); q = yquery (_("Do you want to auto delete previous execution " "log entries when record/replay buffer becomes " - "full (record stop-at-limit)?")); + "full (record full stop-at-limit)?")); if (set_terminal) target_terminal_inferior (); if (q) - record_stop_at_limit = 0; + record_full_stop_at_limit = 0; else error (_("Process record: stopped by user.")); } @@ -569,29 +584,30 @@ record_check_insn_num (int set_terminal) } static void -record_arch_list_cleanups (void *ignore) +record_full_arch_list_cleanups (void *ignore) { - record_list_release (record_arch_list_tail); + record_full_list_release (record_full_arch_list_tail); } /* Before inferior step (when GDB record the running message, inferior only can step), GDB will call this function to record the values to - record_list. This function will call gdbarch_process_record to + record_full_list. This function will call gdbarch_process_record to record the running message of inferior and set them to - record_arch_list, and add it to record_list. */ + record_full_arch_list, and add it to record_full_list. */ static int -record_message (struct regcache *regcache, enum target_signal signal) +record_full_message (struct regcache *regcache, enum gdb_signal signal) { int ret; struct gdbarch *gdbarch = get_regcache_arch (regcache); - struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups, 0); + struct cleanup *old_cleanups + = make_cleanup (record_full_arch_list_cleanups, 0); - record_arch_list_head = NULL; - record_arch_list_tail = NULL; + record_full_arch_list_head = NULL; + record_full_arch_list_tail = NULL; - /* Check record_insn_num. */ - record_check_insn_num (1); + /* Check record_full_insn_num. */ + record_full_check_insn_num (1); /* If gdb sends a signal value to target_resume, save it in the 'end' field of the previous instruction. @@ -614,14 +630,15 @@ record_message (struct regcache *regcache, enum target_signal signal) But we should still deliver the signal to gdb during the replay, if we delivered it during the recording. Therefore we should - record the signal during record_wait, not record_resume. */ - if (record_list != &record_first) /* FIXME better way to check */ + record the signal during record_full_wait, not + record_full_resume. */ + if (record_full_list != &record_full_first) /* FIXME better way to check */ { - gdb_assert (record_list->type == record_end); - record_list->u.end.sigval = signal; + gdb_assert (record_full_list->type == record_full_end); + record_full_list->u.end.sigval = signal; } - if (signal == TARGET_SIGNAL_0 + if (signal == GDB_SIGNAL_0 || !gdbarch_process_record_signal_p (gdbarch)) ret = gdbarch_process_record (gdbarch, regcache, @@ -638,92 +655,96 @@ record_message (struct regcache *regcache, enum target_signal signal) discard_cleanups (old_cleanups); - record_list->next = record_arch_list_head; - record_arch_list_head->prev = record_list; - record_list = record_arch_list_tail; + record_full_list->next = record_full_arch_list_head; + record_full_arch_list_head->prev = record_full_list; + record_full_list = record_full_arch_list_tail; - if (record_insn_num == record_insn_max_num && record_insn_max_num) - record_list_release_first (); + if (record_full_insn_num == record_full_insn_max_num + && record_full_insn_max_num) + record_full_list_release_first (); else - record_insn_num++; + record_full_insn_num++; return 1; } -struct record_message_args { +struct record_full_message_args { struct regcache *regcache; - enum target_signal signal; + enum gdb_signal signal; }; static int -record_message_wrapper (void *args) +record_full_message_wrapper (void *args) { - struct record_message_args *record_args = args; + struct record_full_message_args *record_full_args = args; - return record_message (record_args->regcache, record_args->signal); + return record_full_message (record_full_args->regcache, + record_full_args->signal); } static int -record_message_wrapper_safe (struct regcache *regcache, - enum target_signal signal) +record_full_message_wrapper_safe (struct regcache *regcache, + enum gdb_signal signal) { - struct record_message_args args; + struct record_full_message_args args; args.regcache = regcache; args.signal = signal; - return catch_errors (record_message_wrapper, &args, NULL, RETURN_MASK_ALL); + return catch_errors (record_full_message_wrapper, &args, NULL, + RETURN_MASK_ALL); } -/* Set to 1 if record_store_registers and record_xfer_partial +/* Set to 1 if record_full_store_registers and record_full_xfer_partial doesn't need record. */ -static int record_gdb_operation_disable = 0; +static int record_full_gdb_operation_disable = 0; struct cleanup * -record_gdb_operation_disable_set (void) +record_full_gdb_operation_disable_set (void) { struct cleanup *old_cleanups = NULL; old_cleanups = - make_cleanup_restore_integer (&record_gdb_operation_disable); - record_gdb_operation_disable = 1; + make_cleanup_restore_integer (&record_full_gdb_operation_disable); + record_full_gdb_operation_disable = 1; return old_cleanups; } /* Flag set to TRUE for target_stopped_by_watchpoint. */ -static int record_hw_watchpoint = 0; +static int record_full_hw_watchpoint = 0; /* Execute one instruction from the record log. Each instruction in the log will be represented by an arbitrary sequence of register entries and memory entries, followed by an 'end' entry. */ static inline void -record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, - struct record_entry *entry) +record_full_exec_insn (struct regcache *regcache, + struct gdbarch *gdbarch, + struct record_full_entry *entry) { switch (entry->type) { - case record_reg: /* reg */ + case record_full_reg: /* reg */ { gdb_byte reg[MAX_REGISTER_SIZE]; if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, - "Process record: record_reg %s to " + "Process record: record_full_reg %s to " "inferior num = %d.\n", host_address_to_string (entry), entry->u.reg.num); regcache_cooked_read (regcache, entry->u.reg.num, reg); regcache_cooked_write (regcache, entry->u.reg.num, - record_get_loc (entry)); - memcpy (record_get_loc (entry), reg, entry->u.reg.len); + record_full_get_loc (entry)); + memcpy (record_full_get_loc (entry), reg, entry->u.reg.len); } break; - case record_mem: /* mem */ + case record_full_mem: /* mem */ { /* Nothing to do if the entry is flagged not_accessible. */ if (!entry->u.mem.mem_entry_not_accessible) @@ -732,25 +753,19 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, - "Process record: record_mem %s to " + "Process record: record_full_mem %s to " "inferior addr = %s len = %d.\n", host_address_to_string (entry), paddress (gdbarch, entry->u.mem.addr), entry->u.mem.len); - if (target_read_memory (entry->u.mem.addr, mem, entry->u.mem.len)) - { - entry->u.mem.mem_entry_not_accessible = 1; - if (record_debug) - warning (_("Process record: error reading memory at " - "addr = %s len = %d."), - paddress (gdbarch, entry->u.mem.addr), - entry->u.mem.len); - } + if (record_read_memory (gdbarch, + entry->u.mem.addr, mem, entry->u.mem.len)) + entry->u.mem.mem_entry_not_accessible = 1; else { if (target_write_memory (entry->u.mem.addr, - record_get_loc (entry), + record_full_get_loc (entry), entry->u.mem.len)) { entry->u.mem.mem_entry_not_accessible = 1; @@ -762,7 +777,8 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, } else { - memcpy (record_get_loc (entry), mem, entry->u.mem.len); + memcpy (record_full_get_loc (entry), mem, + entry->u.mem.len); /* We've changed memory --- check if a hardware watchpoint should trap. Note that this @@ -775,7 +791,7 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, if (hardware_watchpoint_inserted_in_range (get_regcache_aspace (regcache), entry->u.mem.addr, entry->u.mem.len)) - record_hw_watchpoint = 1; + record_full_hw_watchpoint = 1; } } } @@ -786,7 +802,7 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, static struct target_ops *tmp_to_resume_ops; static void (*tmp_to_resume) (struct target_ops *, ptid_t, int, - enum target_signal); + enum gdb_signal); static struct target_ops *tmp_to_wait_ops; static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t, struct target_waitstatus *, @@ -812,15 +828,15 @@ static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *); static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *); static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *); -static void record_restore (void); +static void record_full_restore (void); /* Asynchronous signal handle registered as event loop source for when we have pending events ready to be passed to the core. */ -static struct async_event_handler *record_async_inferior_event_token; +static struct async_event_handler *record_full_async_inferior_event_token; static void -record_async_inferior_event_handler (gdb_client_data data) +record_full_async_inferior_event_handler (gdb_client_data data) { inferior_event_handler (INF_REG_EVENT, NULL); } @@ -828,39 +844,40 @@ record_async_inferior_event_handler (gdb_client_data data) /* Open the process record target. */ static void -record_core_open_1 (char *name, int from_tty) +record_full_core_open_1 (char *name, int from_tty) { struct regcache *regcache = get_current_regcache (); int regnum = gdbarch_num_regs (get_regcache_arch (regcache)); int i; - /* Get record_core_regbuf. */ + /* Get record_full_core_regbuf. */ target_fetch_registers (regcache, -1); - record_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum); + record_full_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum); for (i = 0; i < regnum; i ++) regcache_raw_collect (regcache, i, - record_core_regbuf + MAX_REGISTER_SIZE * i); + record_full_core_regbuf + MAX_REGISTER_SIZE * i); - /* Get record_core_start and record_core_end. */ - if (build_section_table (core_bfd, &record_core_start, &record_core_end)) + /* Get record_full_core_start and record_full_core_end. */ + if (build_section_table (core_bfd, &record_full_core_start, + &record_full_core_end)) { - xfree (record_core_regbuf); - record_core_regbuf = NULL; + xfree (record_full_core_regbuf); + record_full_core_regbuf = NULL; error (_("\"%s\": Can't find sections: %s"), bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ())); } - push_target (&record_core_ops); - record_restore (); + push_target (&record_full_core_ops); + record_full_restore (); } /* "to_open" target method for 'live' processes. */ static void -record_open_1 (char *name, int from_tty) +record_full_open_1 (char *name, int from_tty) { if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n"); + fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n"); /* check exec */ if (!target_has_execution) @@ -869,7 +886,7 @@ record_open_1 (char *name, int from_tty) error (_("Process record target can't debug inferior in non-stop mode " "(non-stop).")); - if (!gdbarch_process_record_p (target_gdbarch)) + if (!gdbarch_process_record_p (target_gdbarch ())) error (_("Process record: the current architecture doesn't support " "record function.")); @@ -893,18 +910,20 @@ record_open_1 (char *name, int from_tty) error (_("Could not find 'to_stopped_data_address' " "method on the target stack.")); - push_target (&record_ops); + push_target (&record_full_ops); } +static void record_full_init_record_breakpoints (void); + /* "to_open" target method. Open the process record target. */ static void -record_open (char *name, int from_tty) +record_full_open (char *name, int from_tty) { struct target_ops *t; if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n"); + fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n"); /* Check if record target is already running. */ if (current_target.to_stratum == record_stratum) @@ -964,84 +983,89 @@ record_open (char *name, int from_tty) error (_("Could not find 'to_xfer_partial' method on the target stack.")); /* Reset */ - record_insn_num = 0; - record_insn_count = 0; - record_list = &record_first; - record_list->next = NULL; + record_full_insn_num = 0; + record_full_insn_count = 0; + record_full_list = &record_full_first; + record_full_list->next = NULL; /* Set the tmp beneath pointers to beneath pointers. */ - record_beneath_to_resume_ops = tmp_to_resume_ops; - record_beneath_to_resume = tmp_to_resume; - record_beneath_to_wait_ops = tmp_to_wait_ops; - record_beneath_to_wait = tmp_to_wait; - record_beneath_to_store_registers_ops = tmp_to_store_registers_ops; - record_beneath_to_store_registers = tmp_to_store_registers; - record_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops; - record_beneath_to_xfer_partial = tmp_to_xfer_partial; - record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint; - record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint; - record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint; - record_beneath_to_stopped_data_address = tmp_to_stopped_data_address; - record_beneath_to_async = tmp_to_async; + record_full_beneath_to_resume_ops = tmp_to_resume_ops; + record_full_beneath_to_resume = tmp_to_resume; + record_full_beneath_to_wait_ops = tmp_to_wait_ops; + record_full_beneath_to_wait = tmp_to_wait; + record_full_beneath_to_store_registers_ops = tmp_to_store_registers_ops; + record_full_beneath_to_store_registers = tmp_to_store_registers; + record_full_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops; + record_full_beneath_to_xfer_partial = tmp_to_xfer_partial; + record_full_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint; + record_full_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint; + record_full_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint; + record_full_beneath_to_stopped_data_address = tmp_to_stopped_data_address; + record_full_beneath_to_async = tmp_to_async; if (core_bfd) - record_core_open_1 (name, from_tty); + record_full_core_open_1 (name, from_tty); else - record_open_1 (name, from_tty); + record_full_open_1 (name, from_tty); /* Register extra event sources in the event loop. */ - record_async_inferior_event_token - = create_async_event_handler (record_async_inferior_event_handler, + record_full_async_inferior_event_token + = create_async_event_handler (record_full_async_inferior_event_handler, NULL); + + record_full_init_record_breakpoints (); + + observer_notify_record_changed (current_inferior (), 1); } /* "to_close" target method. Close the process record target. */ static void -record_close (int quitting) +record_full_close (int quitting) { - struct record_core_buf_entry *entry; + struct record_full_core_buf_entry *entry; if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n"); + fprintf_unfiltered (gdb_stdlog, "Process record: record_full_close\n"); - record_list_release (record_list); + record_full_list_release (record_full_list); - /* Release record_core_regbuf. */ - if (record_core_regbuf) + /* Release record_full_core_regbuf. */ + if (record_full_core_regbuf) { - xfree (record_core_regbuf); - record_core_regbuf = NULL; + xfree (record_full_core_regbuf); + record_full_core_regbuf = NULL; } - /* Release record_core_buf_list. */ - if (record_core_buf_list) + /* Release record_full_core_buf_list. */ + if (record_full_core_buf_list) { - for (entry = record_core_buf_list->prev; entry; entry = entry->prev) + for (entry = record_full_core_buf_list->prev; entry; + entry = entry->prev) { - xfree (record_core_buf_list); - record_core_buf_list = entry; + xfree (record_full_core_buf_list); + record_full_core_buf_list = entry; } - record_core_buf_list = NULL; + record_full_core_buf_list = NULL; } - if (record_async_inferior_event_token) - delete_async_event_handler (&record_async_inferior_event_token); + if (record_full_async_inferior_event_token) + delete_async_event_handler (&record_full_async_inferior_event_token); } -static int record_resume_step = 0; +static int record_full_resume_step = 0; -/* True if we've been resumed, and so each record_wait call should - advance execution. If this is false, record_wait will return a +/* True if we've been resumed, and so each record_full_wait call should + advance execution. If this is false, record_full_wait will return a TARGET_WAITKIND_IGNORE. */ -static int record_resumed = 0; +static int record_full_resumed = 0; /* The execution direction of the last resume we got. This is necessary for async mode. Vis (order is not strictly accurate): 1. user has the global execution direction set to forward 2. user does a reverse-step command - 3. record_resume is called with global execution direction + 3. record_full_resume is called with global execution direction temporarily switched to reverse 4. GDB's execution direction is reverted back to forward 5. target record notifies event loop there's an event to handle @@ -1050,23 +1074,23 @@ static int record_resumed = 0; 7. infrun polls an event out of the record target, and handles it 8. GDB goes back to the event loop, and goto #4. */ -static enum exec_direction_kind record_execution_dir = EXEC_FORWARD; +static enum exec_direction_kind record_full_execution_dir = EXEC_FORWARD; /* "to_resume" target method. Resume the process record target. */ static void -record_resume (struct target_ops *ops, ptid_t ptid, int step, - enum target_signal signal) +record_full_resume (struct target_ops *ops, ptid_t ptid, int step, + enum gdb_signal signal) { - record_resume_step = step; - record_resumed = 1; - record_execution_dir = execution_direction; + record_full_resume_step = step; + record_full_resumed = 1; + record_full_execution_dir = execution_direction; - if (!RECORD_IS_REPLAY) + if (!RECORD_FULL_IS_REPLAY) { struct gdbarch *gdbarch = target_thread_architecture (ptid); - record_message (get_current_regcache (), signal); + record_full_message (get_current_regcache (), signal); if (!step) { @@ -1082,7 +1106,7 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step, if (single_step_breakpoints_inserted ()) { /* This is a soft single step. */ - record_resume_step = 1; + record_full_resume_step = 1; } else { @@ -1099,8 +1123,11 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step, } } - record_beneath_to_resume (record_beneath_to_resume_ops, - ptid, step, signal); + /* Make sure the target beneath reports all signals. */ + target_pass_signals (0, NULL); + + record_full_beneath_to_resume (record_full_beneath_to_resume_ops, + ptid, step, signal); } /* We are about to start executing the inferior (or simulate it), @@ -1109,39 +1136,39 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step, { target_async (inferior_event_handler, 0); /* Notify the event loop there's an event to wait for. We do - most of the work in record_wait. */ - mark_async_event_handler (record_async_inferior_event_token); + most of the work in record_full_wait. */ + mark_async_event_handler (record_full_async_inferior_event_token); } } -static int record_get_sig = 0; +static int record_full_get_sig = 0; /* SIGINT signal handler, registered by "to_wait" method. */ static void -record_sig_handler (int signo) +record_full_sig_handler (int signo) { if (record_debug) fprintf_unfiltered (gdb_stdlog, "Process record: get a signal\n"); /* It will break the running inferior in replay mode. */ - record_resume_step = 1; + record_full_resume_step = 1; - /* It will let record_wait set inferior status to get the signal + /* It will let record_full_wait set inferior status to get the signal SIGINT. */ - record_get_sig = 1; + record_full_get_sig = 1; } static void -record_wait_cleanups (void *ignore) +record_full_wait_cleanups (void *ignore) { if (execution_direction == EXEC_REVERSE) { - if (record_list->next) - record_list = record_list->next; + if (record_full_list->next) + record_full_list = record_full_list->next; } else - record_list = record_list->prev; + record_full_list = record_full_list->prev; } /* "to_wait" target method for process record target. @@ -1158,20 +1185,22 @@ record_wait_cleanups (void *ignore) where to stop. */ static ptid_t -record_wait_1 (struct target_ops *ops, - ptid_t ptid, struct target_waitstatus *status, - int options) +record_full_wait_1 (struct target_ops *ops, + ptid_t ptid, struct target_waitstatus *status, + int options) { - struct cleanup *set_cleanups = record_gdb_operation_disable_set (); + struct cleanup *set_cleanups = record_full_gdb_operation_disable_set (); if (record_debug) fprintf_unfiltered (gdb_stdlog, - "Process record: record_wait " - "record_resume_step = %d, record_resumed = %d, direction=%s\n", - record_resume_step, record_resumed, - record_execution_dir == EXEC_FORWARD ? "forward" : "reverse"); - - if (!record_resumed) + "Process record: record_full_wait " + "record_full_resume_step = %d, " + "record_full_resumed = %d, direction=%s\n", + record_full_resume_step, record_full_resumed, + record_full_execution_dir == EXEC_FORWARD + ? "forward" : "reverse"); + + if (!record_full_resumed) { gdb_assert ((options & TARGET_WNOHANG) != 0); @@ -1180,16 +1209,16 @@ record_wait_1 (struct target_ops *ops, return minus_one_ptid; } - record_get_sig = 0; - signal (SIGINT, record_sig_handler); + record_full_get_sig = 0; + signal (SIGINT, record_full_sig_handler); - if (!RECORD_IS_REPLAY && ops != &record_core_ops) + if (!RECORD_FULL_IS_REPLAY && ops != &record_full_core_ops) { - if (record_resume_step) + if (record_full_resume_step) { /* This is a single step. */ - return record_beneath_to_wait (record_beneath_to_wait_ops, - ptid, status, options); + return record_full_beneath_to_wait (record_full_beneath_to_wait_ops, + ptid, status, options); } else { @@ -1200,13 +1229,13 @@ record_wait_1 (struct target_ops *ops, while (1) { - ret = record_beneath_to_wait (record_beneath_to_wait_ops, - ptid, status, options); + ret = record_full_beneath_to_wait + (record_full_beneath_to_wait_ops, ptid, status, options); if (status->kind == TARGET_WAITKIND_IGNORE) { if (record_debug) fprintf_unfiltered (gdb_stdlog, - "Process record: record_wait " + "Process record: record_full_wait " "target beneath not done yet\n"); return ret; } @@ -1214,12 +1243,12 @@ record_wait_1 (struct target_ops *ops, if (single_step_breakpoints_inserted ()) remove_single_step_breakpoints (); - if (record_resume_step) + if (record_full_resume_step) return ret; /* Is this a SIGTRAP? */ if (status->kind == TARGET_WAITKIND_STOPPED - && status->value.sig == TARGET_SIGNAL_TRAP) + && status->value.sig == GDB_SIGNAL_TRAP) { struct regcache *regcache; struct address_space *aspace; @@ -1260,11 +1289,11 @@ record_wait_1 (struct target_ops *ops, But GDB cannot handle it. */ int step = 1; - if (!record_message_wrapper_safe (regcache, - TARGET_SIGNAL_0)) + if (!record_full_message_wrapper_safe (regcache, + GDB_SIGNAL_0)) { status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = TARGET_SIGNAL_0; + status->value.sig = GDB_SIGNAL_0; break; } @@ -1282,11 +1311,12 @@ record_wait_1 (struct target_ops *ops, if (record_debug) fprintf_unfiltered (gdb_stdlog, - "Process record: record_wait " - "issuing one more step in the target beneath\n"); - record_beneath_to_resume (record_beneath_to_resume_ops, - ptid, step, - TARGET_SIGNAL_0); + "Process record: record_full_wait " + "issuing one more step in the " + "target beneath\n"); + record_full_beneath_to_resume + (record_full_beneath_to_resume_ops, ptid, step, + GDB_SIGNAL_0); continue; } } @@ -1304,11 +1334,12 @@ record_wait_1 (struct target_ops *ops, struct gdbarch *gdbarch = get_regcache_arch (regcache); struct address_space *aspace = get_regcache_aspace (regcache); int continue_flag = 1; - int first_record_end = 1; - struct cleanup *old_cleanups = make_cleanup (record_wait_cleanups, 0); + int first_record_full_end = 1; + struct cleanup *old_cleanups + = make_cleanup (record_full_wait_cleanups, 0); CORE_ADDR tmp_pc; - record_hw_watchpoint = 0; + record_full_hw_watchpoint = 0; status->kind = TARGET_WAITKIND_STOPPED; /* Check breakpoint when forward execute. */ @@ -1325,7 +1356,7 @@ record_wait_1 (struct target_ops *ops, paddress (gdbarch, tmp_pc)); if (decr_pc_after_break - && !record_resume_step + && !record_full_resume_step && software_breakpoint_inserted_here_p (aspace, tmp_pc)) regcache_write_pc (regcache, tmp_pc + decr_pc_after_break); @@ -1339,54 +1370,54 @@ record_wait_1 (struct target_ops *ops, Then set it to terminal_ours to make GDB get the signal. */ target_terminal_ours (); - /* In EXEC_FORWARD mode, record_list points to the tail of prev + /* In EXEC_FORWARD mode, record_full_list points to the tail of prev instruction. */ - if (execution_direction == EXEC_FORWARD && record_list->next) - record_list = record_list->next; + if (execution_direction == EXEC_FORWARD && record_full_list->next) + record_full_list = record_full_list->next; - /* Loop over the record_list, looking for the next place to + /* Loop over the record_full_list, looking for the next place to stop. */ do { /* Check for beginning and end of log. */ if (execution_direction == EXEC_REVERSE - && record_list == &record_first) + && record_full_list == &record_full_first) { /* Hit beginning of record log in reverse. */ status->kind = TARGET_WAITKIND_NO_HISTORY; break; } - if (execution_direction != EXEC_REVERSE && !record_list->next) + if (execution_direction != EXEC_REVERSE && !record_full_list->next) { /* Hit end of record log going forward. */ status->kind = TARGET_WAITKIND_NO_HISTORY; break; } - record_exec_insn (regcache, gdbarch, record_list); + record_full_exec_insn (regcache, gdbarch, record_full_list); - if (record_list->type == record_end) + if (record_full_list->type == record_full_end) { if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, - "Process record: record_end %s to " + "Process record: record_full_end %s to " "inferior.\n", - host_address_to_string (record_list)); + host_address_to_string (record_full_list)); - if (first_record_end && execution_direction == EXEC_REVERSE) + if (first_record_full_end && execution_direction == EXEC_REVERSE) { - /* When reverse excute, the first record_end is the part of - current instruction. */ - first_record_end = 0; + /* When reverse excute, the first record_full_end is the + part of current instruction. */ + first_record_full_end = 0; } else { - /* In EXEC_REVERSE mode, this is the record_end of prev + /* In EXEC_REVERSE mode, this is the record_full_end of prev instruction. - In EXEC_FORWARD mode, this is the record_end of current - instruction. */ + In EXEC_FORWARD mode, this is the record_full_end of + current instruction. */ /* step */ - if (record_resume_step) + if (record_full_resume_step) { if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, @@ -1408,7 +1439,7 @@ record_wait_1 (struct target_ops *ops, paddress (gdbarch, tmp_pc)); if (decr_pc_after_break && execution_direction == EXEC_FORWARD - && !record_resume_step + && !record_full_resume_step && software_breakpoint_inserted_here_p (aspace, tmp_pc)) regcache_write_pc (regcache, @@ -1416,7 +1447,7 @@ record_wait_1 (struct target_ops *ops, continue_flag = 0; } - if (record_hw_watchpoint) + if (record_full_hw_watchpoint) { if (record_debug) fprintf_unfiltered (gdb_stdlog, @@ -1425,7 +1456,7 @@ record_wait_1 (struct target_ops *ops, continue_flag = 0; } /* Check target signal */ - if (record_list->u.end.sigval != TARGET_SIGNAL_0) + if (record_full_list->u.end.sigval != GDB_SIGNAL_0) /* FIXME: better way to check */ continue_flag = 0; } @@ -1435,26 +1466,26 @@ record_wait_1 (struct target_ops *ops, { if (execution_direction == EXEC_REVERSE) { - if (record_list->prev) - record_list = record_list->prev; + if (record_full_list->prev) + record_full_list = record_full_list->prev; } else { - if (record_list->next) - record_list = record_list->next; + if (record_full_list->next) + record_full_list = record_full_list->next; } } } while (continue_flag); replay_out: - if (record_get_sig) - status->value.sig = TARGET_SIGNAL_INT; - else if (record_list->u.end.sigval != TARGET_SIGNAL_0) + if (record_full_get_sig) + status->value.sig = GDB_SIGNAL_INT; + else if (record_full_list->u.end.sigval != GDB_SIGNAL_0) /* FIXME: better way to check */ - status->value.sig = record_list->u.end.sigval; + status->value.sig = record_full_list->u.end.sigval; else - status->value.sig = TARGET_SIGNAL_TRAP; + status->value.sig = GDB_SIGNAL_TRAP; discard_cleanups (old_cleanups); } @@ -1466,100 +1497,51 @@ replay_out: } static ptid_t -record_wait (struct target_ops *ops, - ptid_t ptid, struct target_waitstatus *status, - int options) +record_full_wait (struct target_ops *ops, + ptid_t ptid, struct target_waitstatus *status, + int options) { ptid_t return_ptid; - return_ptid = record_wait_1 (ops, ptid, status, options); + return_ptid = record_full_wait_1 (ops, ptid, status, options); if (status->kind != TARGET_WAITKIND_IGNORE) { /* We're reporting a stop. Make sure any spurious target_wait(WNOHANG) doesn't advance the target until the core wants us resumed again. */ - record_resumed = 0; + record_full_resumed = 0; } return return_ptid; } static int -record_stopped_by_watchpoint (void) +record_full_stopped_by_watchpoint (void) { - if (RECORD_IS_REPLAY) - return record_hw_watchpoint; + if (RECORD_FULL_IS_REPLAY) + return record_full_hw_watchpoint; else - return record_beneath_to_stopped_by_watchpoint (); + return record_full_beneath_to_stopped_by_watchpoint (); } static int -record_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) +record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) { - if (RECORD_IS_REPLAY) + if (RECORD_FULL_IS_REPLAY) return 0; else - return record_beneath_to_stopped_data_address (ops, addr_p); -} - -/* "to_disconnect" method for process record target. */ - -static void -record_disconnect (struct target_ops *target, char *args, int from_tty) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_disconnect\n"); - - unpush_target (&record_ops); - target_disconnect (args, from_tty); -} - -/* "to_detach" method for process record target. */ - -static void -record_detach (struct target_ops *ops, char *args, int from_tty) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_detach\n"); - - unpush_target (&record_ops); - target_detach (args, from_tty); -} - -/* "to_mourn_inferior" method for process record target. */ - -static void -record_mourn_inferior (struct target_ops *ops) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: " - "record_mourn_inferior\n"); - - unpush_target (&record_ops); - target_mourn_inferior (); -} - -/* Close process record target before killing the inferior process. */ - -static void -record_kill (struct target_ops *ops) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n"); - - unpush_target (&record_ops); - target_kill (); + return record_full_beneath_to_stopped_data_address (ops, addr_p); } /* Record registers change (by user or by GDB) to list as an instruction. */ static void -record_registers_change (struct regcache *regcache, int regnum) +record_full_registers_change (struct regcache *regcache, int regnum) { - /* Check record_insn_num. */ - record_check_insn_num (0); + /* Check record_full_insn_num. */ + record_full_check_insn_num (0); - record_arch_list_head = NULL; - record_arch_list_tail = NULL; + record_full_arch_list_head = NULL; + record_full_arch_list_tail = NULL; if (regnum < 0) { @@ -1567,45 +1549,47 @@ record_registers_change (struct regcache *regcache, int regnum) for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++) { - if (record_arch_list_add_reg (regcache, i)) + if (record_full_arch_list_add_reg (regcache, i)) { - record_list_release (record_arch_list_tail); + record_full_list_release (record_full_arch_list_tail); error (_("Process record: failed to record execution log.")); } } } else { - if (record_arch_list_add_reg (regcache, regnum)) + if (record_full_arch_list_add_reg (regcache, regnum)) { - record_list_release (record_arch_list_tail); + record_full_list_release (record_full_arch_list_tail); error (_("Process record: failed to record execution log.")); } } - if (record_arch_list_add_end ()) + if (record_full_arch_list_add_end ()) { - record_list_release (record_arch_list_tail); + record_full_list_release (record_full_arch_list_tail); error (_("Process record: failed to record execution log.")); } - record_list->next = record_arch_list_head; - record_arch_list_head->prev = record_list; - record_list = record_arch_list_tail; + record_full_list->next = record_full_arch_list_head; + record_full_arch_list_head->prev = record_full_list; + record_full_list = record_full_arch_list_tail; - if (record_insn_num == record_insn_max_num && record_insn_max_num) - record_list_release_first (); + if (record_full_insn_num == record_full_insn_max_num + && record_full_insn_max_num) + record_full_list_release_first (); else - record_insn_num++; + record_full_insn_num++; } /* "to_store_registers" method for process record target. */ static void -record_store_registers (struct target_ops *ops, struct regcache *regcache, - int regno) +record_full_store_registers (struct target_ops *ops, + struct regcache *regcache, + int regno) { - if (!record_gdb_operation_disable) + if (!record_full_gdb_operation_disable) { - if (RECORD_IS_REPLAY) + if (RECORD_FULL_IS_REPLAY) { int n; @@ -1644,124 +1628,220 @@ record_store_registers (struct target_ops *ops, struct regcache *regcache, } /* Destroy the record from here forward. */ - record_list_release_following (record_list); + record_full_list_release_following (record_full_list); } - record_registers_change (regcache, regno); + record_full_registers_change (regcache, regno); } - record_beneath_to_store_registers (record_beneath_to_store_registers_ops, - regcache, regno); + record_full_beneath_to_store_registers + (record_full_beneath_to_store_registers_ops, regcache, regno); } -/* "to_xfer_partial" method. Behavior is conditional on RECORD_IS_REPLAY. +/* "to_xfer_partial" method. Behavior is conditional on + RECORD_FULL_IS_REPLAY. In replay mode, we cannot write memory unles we are willing to invalidate the record/replay log from this point forward. */ static LONGEST -record_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) +record_full_xfer_partial (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, + LONGEST len) { - if (!record_gdb_operation_disable + if (!record_full_gdb_operation_disable && (object == TARGET_OBJECT_MEMORY || object == TARGET_OBJECT_RAW_MEMORY) && writebuf) { - if (RECORD_IS_REPLAY) + if (RECORD_FULL_IS_REPLAY) { /* Let user choose if he wants to write memory or not. */ if (!query (_("Because GDB is in replay mode, writing to memory " "will make the execution log unusable from this " "point onward. Write memory at address %s?"), - paddress (target_gdbarch, offset))) + paddress (target_gdbarch (), offset))) error (_("Process record canceled the operation.")); /* Destroy the record from here forward. */ - record_list_release_following (record_list); + record_full_list_release_following (record_full_list); } - /* Check record_insn_num */ - record_check_insn_num (0); + /* Check record_full_insn_num */ + record_full_check_insn_num (0); /* Record registers change to list as an instruction. */ - record_arch_list_head = NULL; - record_arch_list_tail = NULL; - if (record_arch_list_add_mem (offset, len)) + record_full_arch_list_head = NULL; + record_full_arch_list_tail = NULL; + if (record_full_arch_list_add_mem (offset, len)) { - record_list_release (record_arch_list_tail); + record_full_list_release (record_full_arch_list_tail); if (record_debug) fprintf_unfiltered (gdb_stdlog, "Process record: failed to record " "execution log."); return -1; } - if (record_arch_list_add_end ()) + if (record_full_arch_list_add_end ()) { - record_list_release (record_arch_list_tail); + record_full_list_release (record_full_arch_list_tail); if (record_debug) fprintf_unfiltered (gdb_stdlog, "Process record: failed to record " "execution log."); return -1; } - record_list->next = record_arch_list_head; - record_arch_list_head->prev = record_list; - record_list = record_arch_list_tail; + record_full_list->next = record_full_arch_list_head; + record_full_arch_list_head->prev = record_full_list; + record_full_list = record_full_arch_list_tail; - if (record_insn_num == record_insn_max_num && record_insn_max_num) - record_list_release_first (); + if (record_full_insn_num == record_full_insn_max_num + && record_full_insn_max_num) + record_full_list_release_first (); else - record_insn_num++; + record_full_insn_num++; } - return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops, - object, annex, readbuf, writebuf, - offset, len); + return record_full_beneath_to_xfer_partial + (record_full_beneath_to_xfer_partial_ops, object, annex, + readbuf, writebuf, offset, len); } -/* Behavior is conditional on RECORD_IS_REPLAY. - We will not actually insert or remove breakpoints when replaying, - nor when recording. */ +/* This structure represents a breakpoint inserted while the record + target is active. We use this to know when to install/remove + breakpoints in/from the target beneath. For example, a breakpoint + may be inserted while recording, but removed when not replaying nor + recording. In that case, the breakpoint had not been inserted on + the target beneath, so we should not try to remove it there. */ -static int -record_insert_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) +struct record_full_breakpoint { - if (!RECORD_IS_REPLAY) + /* The address and address space the breakpoint was set at. */ + struct address_space *address_space; + CORE_ADDR addr; + + /* True when the breakpoint has been also installed in the target + beneath. This will be false for breakpoints set during replay or + when recording. */ + int in_target_beneath; +}; + +typedef struct record_full_breakpoint *record_full_breakpoint_p; +DEF_VEC_P(record_full_breakpoint_p); + +/* The list of breakpoints inserted while the record target is + active. */ +VEC(record_full_breakpoint_p) *record_full_breakpoints = NULL; + +static void +record_full_sync_record_breakpoints (struct bp_location *loc, void *data) +{ + if (loc->loc_type != bp_loc_software_breakpoint) + return; + + if (loc->inserted) { - struct cleanup *old_cleanups = record_gdb_operation_disable_set (); - int ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt); + struct record_full_breakpoint *bp = XNEW (struct record_full_breakpoint); + + bp->addr = loc->target_info.placed_address; + bp->address_space = loc->target_info.placed_address_space; + + bp->in_target_beneath = 1; + VEC_safe_push (record_full_breakpoint_p, record_full_breakpoints, bp); + } +} + +/* Sync existing breakpoints to record_full_breakpoints. */ + +static void +record_full_init_record_breakpoints (void) +{ + VEC_free (record_full_breakpoint_p, record_full_breakpoints); + + iterate_over_bp_locations (record_full_sync_record_breakpoints); +} + +/* Behavior is conditional on RECORD_FULL_IS_REPLAY. We will not actually + insert or remove breakpoints in the real target when replaying, nor + when recording. */ + +static int +record_full_insert_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) +{ + struct record_full_breakpoint *bp; + int in_target_beneath = 0; + + if (!RECORD_FULL_IS_REPLAY) + { + /* When recording, we currently always single-step, so we don't + really need to install regular breakpoints in the inferior. + However, we do have to insert software single-step + breakpoints, in case the target can't hardware step. To keep + things single, we always insert. */ + struct cleanup *old_cleanups; + int ret; + + old_cleanups = record_full_gdb_operation_disable_set (); + ret = record_full_beneath_to_insert_breakpoint (gdbarch, bp_tgt); do_cleanups (old_cleanups); - return ret; + if (ret != 0) + return ret; + + in_target_beneath = 1; } + bp = XNEW (struct record_full_breakpoint); + bp->addr = bp_tgt->placed_address; + bp->address_space = bp_tgt->placed_address_space; + bp->in_target_beneath = in_target_beneath; + VEC_safe_push (record_full_breakpoint_p, record_full_breakpoints, bp); return 0; } /* "to_remove_breakpoint" method for process record target. */ static int -record_remove_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) +record_full_remove_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { - if (!RECORD_IS_REPLAY) + struct record_full_breakpoint *bp; + int ix; + + for (ix = 0; + VEC_iterate (record_full_breakpoint_p, + record_full_breakpoints, ix, bp); + ++ix) { - struct cleanup *old_cleanups = record_gdb_operation_disable_set (); - int ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt); + if (bp->addr == bp_tgt->placed_address + && bp->address_space == bp_tgt->placed_address_space) + { + if (bp->in_target_beneath) + { + struct cleanup *old_cleanups; + int ret; - do_cleanups (old_cleanups); + old_cleanups = record_full_gdb_operation_disable_set (); + ret = record_full_beneath_to_remove_breakpoint (gdbarch, bp_tgt); + do_cleanups (old_cleanups); - return ret; + if (ret != 0) + return ret; + } + + VEC_unordered_remove (record_full_breakpoint_p, + record_full_breakpoints, ix); + return 0; + } } - return 0; + gdb_assert_not_reached ("removing unknown breakpoint"); } /* "to_can_execute_reverse" method for process record target. */ static int -record_can_execute_reverse (void) +record_full_can_execute_reverse (void) { return 1; } @@ -1769,37 +1849,34 @@ record_can_execute_reverse (void) /* "to_get_bookmark" method for process record and prec over core. */ static gdb_byte * -record_get_bookmark (char *args, int from_tty) +record_full_get_bookmark (char *args, int from_tty) { gdb_byte *ret = NULL; /* Return stringified form of instruction count. */ - if (record_list && record_list->type == record_end) - ret = xstrdup (pulongest (record_list->u.end.insn_num)); + if (record_full_list && record_full_list->type == record_full_end) + ret = xstrdup (pulongest (record_full_list->u.end.insn_num)); if (record_debug) { if (ret) fprintf_unfiltered (gdb_stdlog, - "record_get_bookmark returns %s\n", ret); + "record_full_get_bookmark returns %s\n", ret); else fprintf_unfiltered (gdb_stdlog, - "record_get_bookmark returns NULL\n"); + "record_full_get_bookmark returns NULL\n"); } return ret; } -/* The implementation of the command "record goto". */ -static void cmd_record_goto (char *, int); - /* "to_goto_bookmark" method for process record and prec over core. */ static void -record_goto_bookmark (gdb_byte *bookmark, int from_tty) +record_full_goto_bookmark (gdb_byte *bookmark, int from_tty) { if (record_debug) fprintf_unfiltered (gdb_stdlog, - "record_goto_bookmark receives %s\n", bookmark); + "record_full_goto_bookmark receives %s\n", bookmark); if (bookmark[0] == '\'' || bookmark[0] == '\"') { @@ -1810,7 +1887,7 @@ record_goto_bookmark (gdb_byte *bookmark, int from_tty) bookmark[strlen (bookmark) - 1] = '\0'; /* Strip leading quote. */ bookmark++; - /* Pass along to cmd_record_goto. */ + /* Pass along to cmd_record_full_goto. */ } cmd_record_goto ((char *) bookmark, from_tty); @@ -1818,79 +1895,217 @@ record_goto_bookmark (gdb_byte *bookmark, int from_tty) } static void -record_async (void (*callback) (enum inferior_event_type event_type, - void *context), void *context) +record_full_async (void (*callback) (enum inferior_event_type event_type, + void *context), void *context) { /* If we're on top of a line target (e.g., linux-nat, remote), then set it to async mode as well. Will be NULL if we're sitting on top of the core target, for "record restore". */ - if (record_beneath_to_async != NULL) - record_beneath_to_async (callback, context); + if (record_full_beneath_to_async != NULL) + record_full_beneath_to_async (callback, context); } static int -record_can_async_p (void) +record_full_can_async_p (void) { /* We only enable async when the user specifically asks for it. */ return target_async_permitted; } static int -record_is_async_p (void) +record_full_is_async_p (void) { /* We only enable async when the user specifically asks for it. */ return target_async_permitted; } static enum exec_direction_kind -record_execution_direction (void) +record_full_execution_direction (void) +{ + return record_full_execution_dir; +} + +static void +record_full_info (void) +{ + struct record_full_entry *p; + + if (RECORD_FULL_IS_REPLAY) + printf_filtered (_("Replay mode:\n")); + else + printf_filtered (_("Record mode:\n")); + + /* Find entry for first actual instruction in the log. */ + for (p = record_full_first.next; + p != NULL && p->type != record_full_end; + p = p->next) + ; + + /* Do we have a log at all? */ + if (p != NULL && p->type == record_full_end) + { + /* Display instruction number for first instruction in the log. */ + printf_filtered (_("Lowest recorded instruction number is %s.\n"), + pulongest (p->u.end.insn_num)); + + /* If in replay mode, display where we are in the log. */ + if (RECORD_FULL_IS_REPLAY) + printf_filtered (_("Current instruction number is %s.\n"), + pulongest (record_full_list->u.end.insn_num)); + + /* Display instruction number for last instruction in the log. */ + printf_filtered (_("Highest recorded instruction number is %s.\n"), + pulongest (record_full_insn_count)); + + /* Display log count. */ + printf_filtered (_("Log contains %d instructions.\n"), + record_full_insn_num); + } + else + printf_filtered (_("No instructions have been logged.\n")); + + /* Display max log size. */ + printf_filtered (_("Max logged instructions is %d.\n"), + record_full_insn_max_num); +} + +/* The "to_record_delete" target method. */ + +static void +record_full_delete (void) +{ + record_full_list_release_following (record_full_list); +} + +/* The "to_record_is_replaying" target method. */ + +static int +record_full_is_replaying (void) +{ + return RECORD_FULL_IS_REPLAY; +} + +/* Go to a specific entry. */ + +static void +record_full_goto_entry (struct record_full_entry *p) +{ + if (p == NULL) + error (_("Target insn not found.")); + else if (p == record_full_list) + error (_("Already at target insn.")); + else if (p->u.end.insn_num > record_full_list->u.end.insn_num) + { + printf_filtered (_("Go forward to insn number %s\n"), + pulongest (p->u.end.insn_num)); + record_full_goto_insn (p, EXEC_FORWARD); + } + else + { + printf_filtered (_("Go backward to insn number %s\n"), + pulongest (p->u.end.insn_num)); + record_full_goto_insn (p, EXEC_REVERSE); + } + + registers_changed (); + reinit_frame_cache (); + print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); +} + +/* The "to_goto_record_begin" target method. */ + +static void +record_full_goto_begin (void) +{ + struct record_full_entry *p = NULL; + + for (p = &record_full_first; p != NULL; p = p->next) + if (p->type == record_full_end) + break; + + record_full_goto_entry (p); +} + +/* The "to_goto_record_end" target method. */ + +static void +record_full_goto_end (void) +{ + struct record_full_entry *p = NULL; + + for (p = record_full_list; p->next != NULL; p = p->next) + ; + for (; p!= NULL; p = p->prev) + if (p->type == record_full_end) + break; + + record_full_goto_entry (p); +} + +/* The "to_goto_record" target method. */ + +static void +record_full_goto (ULONGEST target_insn) { - return record_execution_dir; + struct record_full_entry *p = NULL; + + for (p = &record_full_first; p != NULL; p = p->next) + if (p->type == record_full_end && p->u.end.insn_num == target_insn) + break; + + record_full_goto_entry (p); } static void -init_record_ops (void) +init_record_full_ops (void) { - record_ops.to_shortname = "record"; - record_ops.to_longname = "Process record and replay target"; - record_ops.to_doc = + record_full_ops.to_shortname = "record-full"; + record_full_ops.to_longname = "Process record and replay target"; + record_full_ops.to_doc = "Log program while executing and replay execution from log."; - record_ops.to_open = record_open; - record_ops.to_close = record_close; - record_ops.to_resume = record_resume; - record_ops.to_wait = record_wait; - record_ops.to_disconnect = record_disconnect; - record_ops.to_detach = record_detach; - record_ops.to_mourn_inferior = record_mourn_inferior; - record_ops.to_kill = record_kill; - record_ops.to_create_inferior = find_default_create_inferior; - record_ops.to_store_registers = record_store_registers; - record_ops.to_xfer_partial = record_xfer_partial; - record_ops.to_insert_breakpoint = record_insert_breakpoint; - record_ops.to_remove_breakpoint = record_remove_breakpoint; - record_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint; - record_ops.to_stopped_data_address = record_stopped_data_address; - record_ops.to_can_execute_reverse = record_can_execute_reverse; - record_ops.to_stratum = record_stratum; + record_full_ops.to_open = record_full_open; + record_full_ops.to_close = record_full_close; + record_full_ops.to_resume = record_full_resume; + record_full_ops.to_wait = record_full_wait; + record_full_ops.to_disconnect = record_disconnect; + record_full_ops.to_detach = record_detach; + record_full_ops.to_mourn_inferior = record_mourn_inferior; + record_full_ops.to_kill = record_kill; + record_full_ops.to_create_inferior = find_default_create_inferior; + record_full_ops.to_store_registers = record_full_store_registers; + record_full_ops.to_xfer_partial = record_full_xfer_partial; + record_full_ops.to_insert_breakpoint = record_full_insert_breakpoint; + record_full_ops.to_remove_breakpoint = record_full_remove_breakpoint; + record_full_ops.to_stopped_by_watchpoint = record_full_stopped_by_watchpoint; + record_full_ops.to_stopped_data_address = record_full_stopped_data_address; + record_full_ops.to_can_execute_reverse = record_full_can_execute_reverse; + record_full_ops.to_stratum = record_stratum; /* Add bookmark target methods. */ - record_ops.to_get_bookmark = record_get_bookmark; - record_ops.to_goto_bookmark = record_goto_bookmark; - record_ops.to_async = record_async; - record_ops.to_can_async_p = record_can_async_p; - record_ops.to_is_async_p = record_is_async_p; - record_ops.to_execution_direction = record_execution_direction; - record_ops.to_magic = OPS_MAGIC; + record_full_ops.to_get_bookmark = record_full_get_bookmark; + record_full_ops.to_goto_bookmark = record_full_goto_bookmark; + record_full_ops.to_async = record_full_async; + record_full_ops.to_can_async_p = record_full_can_async_p; + record_full_ops.to_is_async_p = record_full_is_async_p; + record_full_ops.to_execution_direction = record_full_execution_direction; + record_full_ops.to_info_record = record_full_info; + record_full_ops.to_save_record = record_full_save; + record_full_ops.to_delete_record = record_full_delete; + record_full_ops.to_record_is_replaying = record_full_is_replaying; + record_full_ops.to_goto_record_begin = record_full_goto_begin; + record_full_ops.to_goto_record_end = record_full_goto_end; + record_full_ops.to_goto_record = record_full_goto; + record_full_ops.to_magic = OPS_MAGIC; } /* "to_resume" method for prec over corefile. */ static void -record_core_resume (struct target_ops *ops, ptid_t ptid, int step, - enum target_signal signal) +record_full_core_resume (struct target_ops *ops, ptid_t ptid, int step, + enum gdb_signal signal) { - record_resume_step = step; - record_resumed = 1; - record_execution_dir = execution_direction; + record_full_resume_step = step; + record_full_resumed = 1; + record_full_execution_dir = execution_direction; /* We are about to start executing the inferior (or simulate it), let's register it with the event loop. */ @@ -1899,27 +2114,27 @@ record_core_resume (struct target_ops *ops, ptid_t ptid, int step, target_async (inferior_event_handler, 0); /* Notify the event loop there's an event to wait for. */ - mark_async_event_handler (record_async_inferior_event_token); + mark_async_event_handler (record_full_async_inferior_event_token); } } /* "to_kill" method for prec over corefile. */ static void -record_core_kill (struct target_ops *ops) +record_full_core_kill (struct target_ops *ops) { if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_core_kill\n"); + fprintf_unfiltered (gdb_stdlog, "Process record: record_full_core_kill\n"); - unpush_target (&record_core_ops); + unpush_target (&record_full_core_ops); } /* "to_fetch_registers" method for prec over corefile. */ static void -record_core_fetch_registers (struct target_ops *ops, - struct regcache *regcache, - int regno) +record_full_core_fetch_registers (struct target_ops *ops, + struct regcache *regcache, + int regno) { if (regno < 0) { @@ -1928,30 +2143,30 @@ record_core_fetch_registers (struct target_ops *ops, for (i = 0; i < num; i ++) regcache_raw_supply (regcache, i, - record_core_regbuf + MAX_REGISTER_SIZE * i); + record_full_core_regbuf + MAX_REGISTER_SIZE * i); } else regcache_raw_supply (regcache, regno, - record_core_regbuf + MAX_REGISTER_SIZE * regno); + record_full_core_regbuf + MAX_REGISTER_SIZE * regno); } /* "to_prepare_to_store" method for prec over corefile. */ static void -record_core_prepare_to_store (struct regcache *regcache) +record_full_core_prepare_to_store (struct regcache *regcache) { } /* "to_store_registers" method for prec over corefile. */ static void -record_core_store_registers (struct target_ops *ops, +record_full_core_store_registers (struct target_ops *ops, struct regcache *regcache, int regno) { - if (record_gdb_operation_disable) + if (record_full_gdb_operation_disable) regcache_raw_collect (regcache, regno, - record_core_regbuf + MAX_REGISTER_SIZE * regno); + record_full_core_regbuf + MAX_REGISTER_SIZE * regno); else error (_("You can't do that without a process to debug.")); } @@ -1959,22 +2174,23 @@ record_core_store_registers (struct target_ops *ops, /* "to_xfer_partial" method for prec over corefile. */ static LONGEST -record_core_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, - LONGEST len) +record_full_core_xfer_partial (struct target_ops *ops, + enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, + LONGEST len) { if (object == TARGET_OBJECT_MEMORY) { - if (record_gdb_operation_disable || !writebuf) + if (record_full_gdb_operation_disable || !writebuf) { struct target_section *p; - for (p = record_core_start; p < record_core_end; p++) + for (p = record_full_core_start; p < record_full_core_end; p++) { if (offset >= p->addr) { - struct record_core_buf_entry *entry; + struct record_full_core_buf_entry *entry; ULONGEST sec_offset; if (offset >= p->endaddr) @@ -1994,8 +2210,8 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object, memset (readbuf, 0, len); return len; } - /* Get record_core_buf_entry. */ - for (entry = record_core_buf_list; entry; + /* Get record_full_core_buf_entry. */ + for (entry = record_full_core_buf_list; entry; entry = entry->prev) if (entry->p == p) break; @@ -2004,8 +2220,9 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object, if (!entry) { /* Add a new entry. */ - entry = (struct record_core_buf_entry *) - xmalloc (sizeof (struct record_core_buf_entry)); + entry = (struct record_full_core_buf_entry *) + xmalloc + (sizeof (struct record_full_core_buf_entry)); entry->p = p; if (!bfd_malloc_and_get_section (p->bfd, p->the_bfd_section, @@ -2014,8 +2231,8 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object, xfree (entry); return 0; } - entry->prev = record_core_buf_list; - record_core_buf_list = entry; + entry->prev = record_full_core_buf_list; + record_full_core_buf_list = entry; } memcpy (entry->buf + sec_offset, writebuf, @@ -2024,8 +2241,8 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object, else { if (!entry) - return record_beneath_to_xfer_partial - (record_beneath_to_xfer_partial_ops, + return record_full_beneath_to_xfer_partial + (record_full_beneath_to_xfer_partial_ops, object, annex, readbuf, writebuf, offset, len); @@ -2043,16 +2260,16 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object, error (_("You can't do that without a process to debug.")); } - return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops, - object, annex, readbuf, writebuf, - offset, len); + return record_full_beneath_to_xfer_partial + (record_full_beneath_to_xfer_partial_ops, object, annex, + readbuf, writebuf, offset, len); } /* "to_insert_breakpoint" method for prec over corefile. */ static int -record_core_insert_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) +record_full_core_insert_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { return 0; } @@ -2060,8 +2277,8 @@ record_core_insert_breakpoint (struct gdbarch *gdbarch, /* "to_remove_breakpoint" method for prec over corefile. */ static int -record_core_remove_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) +record_full_core_remove_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { return 0; } @@ -2069,186 +2286,54 @@ record_core_remove_breakpoint (struct gdbarch *gdbarch, /* "to_has_execution" method for prec over corefile. */ static int -record_core_has_execution (struct target_ops *ops, ptid_t the_ptid) +record_full_core_has_execution (struct target_ops *ops, ptid_t the_ptid) { return 1; } static void -init_record_core_ops (void) +init_record_full_core_ops (void) { - record_core_ops.to_shortname = "record-core"; - record_core_ops.to_longname = "Process record and replay target"; - record_core_ops.to_doc = + record_full_core_ops.to_shortname = "record-core"; + record_full_core_ops.to_longname = "Process record and replay target"; + record_full_core_ops.to_doc = "Log program while executing and replay execution from log."; - record_core_ops.to_open = record_open; - record_core_ops.to_close = record_close; - record_core_ops.to_resume = record_core_resume; - record_core_ops.to_wait = record_wait; - record_core_ops.to_kill = record_core_kill; - record_core_ops.to_fetch_registers = record_core_fetch_registers; - record_core_ops.to_prepare_to_store = record_core_prepare_to_store; - record_core_ops.to_store_registers = record_core_store_registers; - record_core_ops.to_xfer_partial = record_core_xfer_partial; - record_core_ops.to_insert_breakpoint = record_core_insert_breakpoint; - record_core_ops.to_remove_breakpoint = record_core_remove_breakpoint; - record_core_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint; - record_core_ops.to_stopped_data_address = record_stopped_data_address; - record_core_ops.to_can_execute_reverse = record_can_execute_reverse; - record_core_ops.to_has_execution = record_core_has_execution; - record_core_ops.to_stratum = record_stratum; + record_full_core_ops.to_open = record_full_open; + record_full_core_ops.to_close = record_full_close; + record_full_core_ops.to_resume = record_full_core_resume; + record_full_core_ops.to_wait = record_full_wait; + record_full_core_ops.to_kill = record_full_core_kill; + record_full_core_ops.to_fetch_registers = record_full_core_fetch_registers; + record_full_core_ops.to_prepare_to_store = record_full_core_prepare_to_store; + record_full_core_ops.to_store_registers = record_full_core_store_registers; + record_full_core_ops.to_xfer_partial = record_full_core_xfer_partial; + record_full_core_ops.to_insert_breakpoint + = record_full_core_insert_breakpoint; + record_full_core_ops.to_remove_breakpoint + = record_full_core_remove_breakpoint; + record_full_core_ops.to_stopped_by_watchpoint + = record_full_stopped_by_watchpoint; + record_full_core_ops.to_stopped_data_address + = record_full_stopped_data_address; + record_full_core_ops.to_can_execute_reverse + = record_full_can_execute_reverse; + record_full_core_ops.to_has_execution = record_full_core_has_execution; + record_full_core_ops.to_stratum = record_stratum; /* Add bookmark target methods. */ - record_core_ops.to_get_bookmark = record_get_bookmark; - record_core_ops.to_goto_bookmark = record_goto_bookmark; - record_core_ops.to_async = record_async; - record_core_ops.to_can_async_p = record_can_async_p; - record_core_ops.to_is_async_p = record_is_async_p; - record_core_ops.to_execution_direction = record_execution_direction; - record_core_ops.to_magic = OPS_MAGIC; -} - -/* Implement "show record debug" command. */ - -static void -show_record_debug (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) -{ - fprintf_filtered (file, _("Debugging of process record target is %s.\n"), - value); -} - -/* Alias for "target record". */ - -static void -cmd_record_start (char *args, int from_tty) -{ - execute_command ("target record", from_tty); -} - -/* Truncate the record log from the present point - of replay until the end. */ - -static void -cmd_record_delete (char *args, int from_tty) -{ - if (current_target.to_stratum == record_stratum) - { - if (RECORD_IS_REPLAY) - { - if (!from_tty || query (_("Delete the log from this point forward " - "and begin to record the running message " - "at current PC?"))) - record_list_release_following (record_list); - } - else - printf_unfiltered (_("Already at end of record list.\n")); - - } - else - printf_unfiltered (_("Process record is not started.\n")); -} - -/* Implement the "stoprecord" or "record stop" command. */ - -static void -cmd_record_stop (char *args, int from_tty) -{ - if (current_target.to_stratum == record_stratum) - { - unpush_target (&record_ops); - printf_unfiltered (_("Process record is stopped and all execution " - "logs are deleted.\n")); - } - else - printf_unfiltered (_("Process record is not started.\n")); -} - -/* Set upper limit of record log size. */ - -static void -set_record_insn_max_num (char *args, int from_tty, struct cmd_list_element *c) -{ - if (record_insn_num > record_insn_max_num && record_insn_max_num) - { - /* Count down record_insn_num while releasing records from list. */ - while (record_insn_num > record_insn_max_num) - { - record_list_release_first (); - record_insn_num--; - } - } -} - -static struct cmd_list_element *record_cmdlist, *set_record_cmdlist, - *show_record_cmdlist, *info_record_cmdlist; - -static void -set_record_command (char *args, int from_tty) -{ - printf_unfiltered (_("\"set record\" must be followed " - "by an apporpriate subcommand.\n")); - help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout); -} - -static void -show_record_command (char *args, int from_tty) -{ - cmd_show_list (show_record_cmdlist, from_tty, ""); -} - -/* Display some statistics about the execution log. */ - -static void -info_record_command (char *args, int from_tty) -{ - struct record_entry *p; - - if (current_target.to_stratum == record_stratum) - { - if (RECORD_IS_REPLAY) - printf_filtered (_("Replay mode:\n")); - else - printf_filtered (_("Record mode:\n")); - - /* Find entry for first actual instruction in the log. */ - for (p = record_first.next; - p != NULL && p->type != record_end; - p = p->next) - ; - - /* Do we have a log at all? */ - if (p != NULL && p->type == record_end) - { - /* Display instruction number for first instruction in the log. */ - printf_filtered (_("Lowest recorded instruction number is %s.\n"), - pulongest (p->u.end.insn_num)); - - /* If in replay mode, display where we are in the log. */ - if (RECORD_IS_REPLAY) - printf_filtered (_("Current instruction number is %s.\n"), - pulongest (record_list->u.end.insn_num)); - - /* Display instruction number for last instruction in the log. */ - printf_filtered (_("Highest recorded instruction number is %s.\n"), - pulongest (record_insn_count)); - - /* Display log count. */ - printf_filtered (_("Log contains %d instructions.\n"), - record_insn_num); - } - else - { - printf_filtered (_("No instructions have been logged.\n")); - } - } - else - { - printf_filtered (_("target record is not active.\n")); - } - - /* Display max log size. */ - printf_filtered (_("Max logged instructions is %d.\n"), - record_insn_max_num); + record_full_core_ops.to_get_bookmark = record_full_get_bookmark; + record_full_core_ops.to_goto_bookmark = record_full_goto_bookmark; + record_full_core_ops.to_async = record_full_async; + record_full_core_ops.to_can_async_p = record_full_can_async_p; + record_full_core_ops.to_is_async_p = record_full_is_async_p; + record_full_core_ops.to_execution_direction + = record_full_execution_direction; + record_full_core_ops.to_info_record = record_full_info; + record_full_core_ops.to_delete_record = record_full_delete; + record_full_core_ops.to_record_is_replaying = record_full_is_replaying; + record_full_core_ops.to_goto_record_begin = record_full_goto_begin; + record_full_core_ops.to_goto_record_end = record_full_goto_end; + record_full_core_ops.to_goto_record = record_full_goto; + record_full_core_ops.to_magic = OPS_MAGIC; } /* Record log save-file format @@ -2259,14 +2344,14 @@ info_record_command (char *args, int from_tty) NOTE: be sure to change whenever this file format changes! Records: - record_end: - 1 byte: record type (record_end, see enum record_type). - record_reg: - 1 byte: record type (record_reg, see enum record_type). + record_full_end: + 1 byte: record type (record_full_end, see enum record_full_type). + record_full_reg: + 1 byte: record type (record_full_reg, see enum record_full_type). 8 bytes: register id (network byte order). MAX_REGISTER_SIZE bytes: register value. - record_mem: - 1 byte: record type (record_mem, see enum record_type). + record_full_mem: + 1 byte: record type (record_full_mem, see enum record_full_type). 8 bytes: memory length (network byte order). 8 bytes: memory address (network byte order). n bytes: memory value (n == memory length). @@ -2276,17 +2361,17 @@ info_record_command (char *args, int from_tty) NOTE: be sure to change whenever this file format changes! Records: - record_end: - 1 byte: record type (record_end, see enum record_type). + record_full_end: + 1 byte: record type (record_full_end, see enum record_full_type). 4 bytes: signal 4 bytes: instruction count - record_reg: - 1 byte: record type (record_reg, see enum record_type). + record_full_reg: + 1 byte: record type (record_full_reg, see enum record_full_type). 4 bytes: register id (network byte order). n bytes: register value (n == actual register size). (eg. 4 bytes for x86 general registers). - record_mem: - 1 byte: record type (record_mem, see enum record_type). + record_full_mem: + 1 byte: record type (record_full_mem, see enum record_full_type). 4 bytes: memory length (network byte order). 8 bytes: memory address (network byte order). n bytes: memory value (n == memory length). @@ -2340,11 +2425,11 @@ netorder16 (uint16_t input) /* Restore the execution log from a core_bfd file. */ static void -record_restore (void) +record_full_restore (void) { uint32_t magic; struct cleanup *old_cleanups; - struct record_entry *rec; + struct record_full_entry *rec; asection *osec; uint32_t osec_size; int bfd_offset = 0; @@ -2355,8 +2440,8 @@ record_restore (void) if (core_bfd == NULL) return; - /* "record_restore" can only be called when record list is empty. */ - gdb_assert (record_first.next == NULL); + /* "record_full_restore" can only be called when record list is empty. */ + gdb_assert (record_full_first.next == NULL); if (record_debug) fprintf_unfiltered (gdb_stdlog, "Restoring recording from core file.\n"); @@ -2374,21 +2459,21 @@ record_restore (void) /* Check the magic code. */ bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset); - if (magic != RECORD_FILE_MAGIC) + if (magic != RECORD_FULL_FILE_MAGIC) error (_("Version mis-match or file format error in core file %s."), bfd_get_filename (core_bfd)); if (record_debug) fprintf_unfiltered (gdb_stdlog, " Reading 4-byte magic cookie " - "RECORD_FILE_MAGIC (0x%s)\n", + "RECORD_FULL_FILE_MAGIC (0x%s)\n", phex_nz (netorder32 (magic), 4)); - /* Restore the entries in recfd into record_arch_list_head and - record_arch_list_tail. */ - record_arch_list_head = NULL; - record_arch_list_tail = NULL; - record_insn_num = 0; - old_cleanups = make_cleanup (record_arch_list_cleanups, 0); + /* Restore the entries in recfd into record_full_arch_list_head and + record_full_arch_list_tail. */ + record_full_arch_list_head = NULL; + record_full_arch_list_tail = NULL; + record_full_insn_num = 0; + old_cleanups = make_cleanup (record_full_arch_list_cleanups, 0); regcache = get_current_regcache (); while (1) @@ -2404,16 +2489,16 @@ record_restore (void) switch (rectype) { - case record_reg: /* reg */ + case record_full_reg: /* reg */ /* Get register number to regnum. */ bfdcore_read (core_bfd, osec, ®num, sizeof (regnum), &bfd_offset); regnum = netorder32 (regnum); - rec = record_reg_alloc (regcache, regnum); + rec = record_full_reg_alloc (regcache, regnum); /* Get val. */ - bfdcore_read (core_bfd, osec, record_get_loc (rec), + bfdcore_read (core_bfd, osec, record_full_get_loc (rec), rec->u.reg.len, &bfd_offset); if (record_debug) @@ -2425,7 +2510,7 @@ record_restore (void) rec->u.reg.len); break; - case record_mem: /* mem */ + case record_full_mem: /* mem */ /* Get len. */ bfdcore_read (core_bfd, osec, &len, sizeof (len), &bfd_offset); @@ -2436,10 +2521,10 @@ record_restore (void) sizeof (addr), &bfd_offset); addr = netorder64 (addr); - rec = record_mem_alloc (addr, len); + rec = record_full_mem_alloc (addr, len); /* Get val. */ - bfdcore_read (core_bfd, osec, record_get_loc (rec), + bfdcore_read (core_bfd, osec, record_full_get_loc (rec), rec->u.mem.len, &bfd_offset); if (record_debug) @@ -2453,9 +2538,9 @@ record_restore (void) rec->u.mem.len); break; - case record_end: /* end */ - rec = record_end_alloc (); - record_insn_num ++; + case record_full_end: /* end */ + rec = record_full_end_alloc (); + record_full_insn_num ++; /* Get signal value. */ bfdcore_read (core_bfd, osec, &signal, @@ -2468,10 +2553,10 @@ record_restore (void) sizeof (count), &bfd_offset); count = netorder32 (count); rec->u.end.insn_num = count; - record_insn_count = count + 1; + record_full_insn_count = count + 1; if (record_debug) fprintf_unfiltered (gdb_stdlog, - " Reading record_end (1 + " + " Reading record_full_end (1 + " "%lu + %lu bytes), offset == %s\n", (unsigned long) sizeof (signal), (unsigned long) sizeof (count), @@ -2486,23 +2571,23 @@ record_restore (void) } /* Add rec to record arch list. */ - record_arch_list_add (rec); + record_full_arch_list_add (rec); } discard_cleanups (old_cleanups); - /* Add record_arch_list_head to the end of record list. */ - record_first.next = record_arch_list_head; - record_arch_list_head->prev = &record_first; - record_arch_list_tail->next = NULL; - record_list = &record_first; + /* Add record_full_arch_list_head to the end of record list. */ + record_full_first.next = record_full_arch_list_head; + record_full_arch_list_head->prev = &record_full_first; + record_full_arch_list_tail->next = NULL; + record_full_list = &record_full_first; - /* Update record_insn_max_num. */ - if (record_insn_num > record_insn_max_num) + /* Update record_full_insn_max_num. */ + if (record_full_insn_num > record_full_insn_max_num) { - record_insn_max_num = record_insn_num; + record_full_insn_max_num = record_full_insn_num; warning (_("Auto increase record/replay buffer limit to %d."), - record_insn_max_num); + record_full_insn_max_num); } /* Succeeded. */ @@ -2531,19 +2616,19 @@ bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset) corefile format, with an extra section for our data. */ static void -cmd_record_restore (char *args, int from_tty) +cmd_record_full_restore (char *args, int from_tty) { core_file_command (args, from_tty); - record_open (args, from_tty); + record_full_open (args, from_tty); } static void -record_save_cleanups (void *data) +record_full_save_cleanups (void *data) { bfd *obfd = data; char *pathname = xstrdup (bfd_get_filename (obfd)); - bfd_close (obfd); + gdb_bfd_unref (obfd); unlink (pathname); xfree (pathname); } @@ -2552,10 +2637,9 @@ record_save_cleanups (void *data) format, with an extra section for our data. */ static void -cmd_record_save (char *args, int from_tty) +record_full_save (char *recfilename) { - char *recfilename, recfilename_buffer[40]; - struct record_entry *cur_record_list; + struct record_full_entry *cur_record_full_list; uint32_t magic; struct regcache *regcache; struct gdbarch *gdbarch; @@ -2566,20 +2650,6 @@ cmd_record_save (char *args, int from_tty) asection *osec = NULL; int bfd_offset = 0; - if (strcmp (current_target.to_shortname, "record") != 0) - error (_("This command can only be used with target 'record'.\n" - "Use 'target record' first.\n")); - - if (args && *args) - recfilename = args; - else - { - /* Default recfile name is "gdb_record.PID". */ - snprintf (recfilename_buffer, sizeof (recfilename_buffer), - "gdb_record.%d", PIDGET (inferior_ptid)); - recfilename = recfilename_buffer; - } - /* Open the save file. */ if (record_debug) fprintf_unfiltered (gdb_stdlog, "Saving execution log to core file '%s'\n", @@ -2587,45 +2657,45 @@ cmd_record_save (char *args, int from_tty) /* Open the output file. */ obfd = create_gcore_bfd (recfilename); - old_cleanups = make_cleanup (record_save_cleanups, obfd); + old_cleanups = make_cleanup (record_full_save_cleanups, obfd); - /* Save the current record entry to "cur_record_list". */ - cur_record_list = record_list; + /* Save the current record entry to "cur_record_full_list". */ + cur_record_full_list = record_full_list; /* Get the values of regcache and gdbarch. */ regcache = get_current_regcache (); gdbarch = get_regcache_arch (regcache); /* Disable the GDB operation record. */ - set_cleanups = record_gdb_operation_disable_set (); + set_cleanups = record_full_gdb_operation_disable_set (); /* Reverse execute to the begin of record list. */ while (1) { /* Check for beginning and end of log. */ - if (record_list == &record_first) + if (record_full_list == &record_full_first) break; - record_exec_insn (regcache, gdbarch, record_list); + record_full_exec_insn (regcache, gdbarch, record_full_list); - if (record_list->prev) - record_list = record_list->prev; + if (record_full_list->prev) + record_full_list = record_full_list->prev; } /* Compute the size needed for the extra bfd section. */ save_size = 4; /* magic cookie */ - for (record_list = record_first.next; record_list; - record_list = record_list->next) - switch (record_list->type) + for (record_full_list = record_full_first.next; record_full_list; + record_full_list = record_full_list->next) + switch (record_full_list->type) { - case record_end: + case record_full_end: save_size += 1 + 4 + 4; break; - case record_reg: - save_size += 1 + 4 + record_list->u.reg.len; + case record_full_reg: + save_size += 1 + 4 + record_full_list->u.reg.len; break; - case record_mem: - save_size += 1 + 4 + 8 + record_list->u.mem.len; + case record_full_mem: + save_size += 1 + 4 + 8 + record_full_list->u.mem.len; break; } @@ -2647,89 +2717,91 @@ cmd_record_save (char *args, int from_tty) /* Write out the record log. */ /* Write the magic code. */ - magic = RECORD_FILE_MAGIC; + magic = RECORD_FULL_FILE_MAGIC; if (record_debug) fprintf_unfiltered (gdb_stdlog, " Writing 4-byte magic cookie " - "RECORD_FILE_MAGIC (0x%s)\n", + "RECORD_FULL_FILE_MAGIC (0x%s)\n", phex_nz (magic, 4)); bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset); /* Save the entries to recfd and forward execute to the end of record list. */ - record_list = &record_first; + record_full_list = &record_full_first; while (1) { /* Save entry. */ - if (record_list != &record_first) + if (record_full_list != &record_full_first) { uint8_t type; uint32_t regnum, len, signal, count; uint64_t addr; - type = record_list->type; + type = record_full_list->type; bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset); - switch (record_list->type) + switch (record_full_list->type) { - case record_reg: /* reg */ + case record_full_reg: /* reg */ if (record_debug) fprintf_unfiltered (gdb_stdlog, " Writing register %d (1 " "plus %lu plus %d bytes)\n", - record_list->u.reg.num, + record_full_list->u.reg.num, (unsigned long) sizeof (regnum), - record_list->u.reg.len); + record_full_list->u.reg.len); /* Write regnum. */ - regnum = netorder32 (record_list->u.reg.num); + regnum = netorder32 (record_full_list->u.reg.num); bfdcore_write (obfd, osec, ®num, sizeof (regnum), &bfd_offset); /* Write regval. */ - bfdcore_write (obfd, osec, record_get_loc (record_list), - record_list->u.reg.len, &bfd_offset); + bfdcore_write (obfd, osec, + record_full_get_loc (record_full_list), + record_full_list->u.reg.len, &bfd_offset); break; - case record_mem: /* mem */ + case record_full_mem: /* mem */ if (record_debug) fprintf_unfiltered (gdb_stdlog, " Writing memory %s (1 plus " "%lu plus %lu plus %d bytes)\n", paddress (gdbarch, - record_list->u.mem.addr), + record_full_list->u.mem.addr), (unsigned long) sizeof (addr), (unsigned long) sizeof (len), - record_list->u.mem.len); + record_full_list->u.mem.len); /* Write memlen. */ - len = netorder32 (record_list->u.mem.len); + len = netorder32 (record_full_list->u.mem.len); bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset); /* Write memaddr. */ - addr = netorder64 (record_list->u.mem.addr); + addr = netorder64 (record_full_list->u.mem.addr); bfdcore_write (obfd, osec, &addr, sizeof (addr), &bfd_offset); /* Write memval. */ - bfdcore_write (obfd, osec, record_get_loc (record_list), - record_list->u.mem.len, &bfd_offset); + bfdcore_write (obfd, osec, + record_full_get_loc (record_full_list), + record_full_list->u.mem.len, &bfd_offset); break; - case record_end: + case record_full_end: if (record_debug) fprintf_unfiltered (gdb_stdlog, - " Writing record_end (1 + " + " Writing record_full_end (1 + " "%lu + %lu bytes)\n", (unsigned long) sizeof (signal), (unsigned long) sizeof (count)); /* Write signal value. */ - signal = netorder32 (record_list->u.end.sigval); + signal = netorder32 (record_full_list->u.end.sigval); bfdcore_write (obfd, osec, &signal, sizeof (signal), &bfd_offset); /* Write insn count. */ - count = netorder32 (record_list->u.end.insn_num); + count = netorder32 (record_full_list->u.end.insn_num); bfdcore_write (obfd, osec, &count, sizeof (count), &bfd_offset); break; @@ -2737,29 +2809,29 @@ cmd_record_save (char *args, int from_tty) } /* Execute entry. */ - record_exec_insn (regcache, gdbarch, record_list); + record_full_exec_insn (regcache, gdbarch, record_full_list); - if (record_list->next) - record_list = record_list->next; + if (record_full_list->next) + record_full_list = record_full_list->next; else break; } - /* Reverse execute to cur_record_list. */ + /* Reverse execute to cur_record_full_list. */ while (1) { /* Check for beginning and end of log. */ - if (record_list == cur_record_list) + if (record_full_list == cur_record_full_list) break; - record_exec_insn (regcache, gdbarch, record_list); + record_full_exec_insn (regcache, gdbarch, record_full_list); - if (record_list->prev) - record_list = record_list->prev; + if (record_full_list->prev) + record_full_list = record_full_list->prev; } do_cleanups (set_cleanups); - bfd_close (obfd); + gdb_bfd_unref (obfd); discard_cleanups (old_cleanups); /* Succeeded. */ @@ -2767,15 +2839,15 @@ cmd_record_save (char *args, int from_tty) recfilename); } -/* record_goto_insn -- rewind the record log (forward or backward, +/* record_full_goto_insn -- rewind the record log (forward or backward, depending on DIR) to the given entry, changing the program state correspondingly. */ static void -record_goto_insn (struct record_entry *entry, - enum exec_direction_kind dir) +record_full_goto_insn (struct record_full_entry *entry, + enum exec_direction_kind dir) { - struct cleanup *set_cleanups = record_gdb_operation_disable_set (); + struct cleanup *set_cleanups = record_full_gdb_operation_disable_set (); struct regcache *regcache = get_current_regcache (); struct gdbarch *gdbarch = get_regcache_arch (regcache); @@ -2783,154 +2855,108 @@ record_goto_insn (struct record_entry *entry, and we will not hit the end of the recording. */ if (dir == EXEC_FORWARD) - record_list = record_list->next; + record_full_list = record_full_list->next; do { - record_exec_insn (regcache, gdbarch, record_list); + record_full_exec_insn (regcache, gdbarch, record_full_list); if (dir == EXEC_REVERSE) - record_list = record_list->prev; + record_full_list = record_full_list->prev; else - record_list = record_list->next; - } while (record_list != entry); + record_full_list = record_full_list->next; + } while (record_full_list != entry); do_cleanups (set_cleanups); } -/* "record goto" command. Argument is an instruction number, - as given by "info record". - - Rewinds the recording (forward or backward) to the given instruction. */ +/* Alias for "target record-full". */ static void -cmd_record_goto (char *arg, int from_tty) +cmd_record_full_start (char *args, int from_tty) { - struct record_entry *p = NULL; - ULONGEST target_insn = 0; - - if (arg == NULL || *arg == '\0') - error (_("Command requires an argument (insn number to go to).")); + execute_command ("target record-full", from_tty); +} - if (strncmp (arg, "start", strlen ("start")) == 0 - || strncmp (arg, "begin", strlen ("begin")) == 0) - { - /* Special case. Find first insn. */ - for (p = &record_first; p != NULL; p = p->next) - if (p->type == record_end) - break; - if (p) - target_insn = p->u.end.insn_num; - } - else if (strncmp (arg, "end", strlen ("end")) == 0) +static void +set_record_full_insn_max_num (char *args, int from_tty, + struct cmd_list_element *c) +{ + if (record_full_insn_num > record_full_insn_max_num + && record_full_insn_max_num) { - /* Special case. Find last insn. */ - for (p = record_list; p->next != NULL; p = p->next) - ; - for (; p!= NULL; p = p->prev) - if (p->type == record_end) - break; - if (p) - target_insn = p->u.end.insn_num; + /* Count down record_full_insn_num while releasing records from list. */ + while (record_full_insn_num > record_full_insn_max_num) + { + record_full_list_release_first (); + record_full_insn_num--; + } } - else - { - /* General case. Find designated insn. */ - target_insn = parse_and_eval_long (arg); +} - for (p = &record_first; p != NULL; p = p->next) - if (p->type == record_end && p->u.end.insn_num == target_insn) - break; - } +/* The "set record full" command. */ - if (p == NULL) - error (_("Target insn '%s' not found."), arg); - else if (p == record_list) - error (_("Already at insn '%s'."), arg); - else if (p->u.end.insn_num > record_list->u.end.insn_num) - { - printf_filtered (_("Go forward to insn number %s\n"), - pulongest (target_insn)); - record_goto_insn (p, EXEC_FORWARD); - } - else - { - printf_filtered (_("Go backward to insn number %s\n"), - pulongest (target_insn)); - record_goto_insn (p, EXEC_REVERSE); - } - registers_changed (); - reinit_frame_cache (); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); +static void +set_record_full_command (char *args, int from_tty) +{ + printf_unfiltered (_("\"set record full\" must be followed " + "by an apporpriate subcommand.\n")); + help_list (set_record_full_cmdlist, "set record full ", all_commands, + gdb_stdout); } +/* The "show record full" command. */ + +static void +show_record_full_command (char *args, int from_tty) +{ + cmd_show_list (show_record_full_cmdlist, from_tty, ""); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_record_full; + void -_initialize_record (void) +_initialize_record_full (void) { struct cmd_list_element *c; - /* Init record_first. */ - record_first.prev = NULL; - record_first.next = NULL; - record_first.type = record_end; - - init_record_ops (); - add_target (&record_ops); - init_record_core_ops (); - add_target (&record_core_ops); - - add_setshow_zinteger_cmd ("record", no_class, &record_debug, - _("Set debugging of record/replay feature."), - _("Show debugging of record/replay feature."), - _("When enabled, debugging output for " - "record/replay feature is displayed."), - NULL, show_record_debug, &setdebuglist, - &showdebuglist); - - c = add_prefix_cmd ("record", class_obscure, cmd_record_start, - _("Abbreviated form of \"target record\" command."), - &record_cmdlist, "record ", 0, &cmdlist); - set_cmd_completer (c, filename_completer); + /* Init record_full_first. */ + record_full_first.prev = NULL; + record_full_first.next = NULL; + record_full_first.type = record_full_end; - add_com_alias ("rec", "record", class_obscure, 1); - add_prefix_cmd ("record", class_support, set_record_command, - _("Set record options"), &set_record_cmdlist, - "set record ", 0, &setlist); - add_alias_cmd ("rec", "record", class_obscure, 1, &setlist); - add_prefix_cmd ("record", class_support, show_record_command, - _("Show record options"), &show_record_cmdlist, - "show record ", 0, &showlist); - add_alias_cmd ("rec", "record", class_obscure, 1, &showlist); - add_prefix_cmd ("record", class_support, info_record_command, - _("Info record options"), &info_record_cmdlist, - "info record ", 0, &infolist); - add_alias_cmd ("rec", "record", class_obscure, 1, &infolist); - - c = add_cmd ("save", class_obscure, cmd_record_save, - _("Save the execution log to a file.\n\ -Argument is optional filename.\n\ -Default filename is 'gdb_record.'."), - &record_cmdlist); - set_cmd_completer (c, filename_completer); + init_record_full_ops (); + add_target (&record_full_ops); + add_deprecated_target_alias (&record_full_ops, "record"); + init_record_full_core_ops (); + add_target (&record_full_core_ops); - c = add_cmd ("restore", class_obscure, cmd_record_restore, + add_prefix_cmd ("full", class_obscure, cmd_record_full_start, + _("Start full execution recording."), &record_full_cmdlist, + "record full ", 0, &record_cmdlist); + + c = add_cmd ("restore", class_obscure, cmd_record_full_restore, _("Restore the execution log from a file.\n\ Argument is filename. File must be created with 'record save'."), - &record_cmdlist); + &record_full_cmdlist); + set_cmd_completer (c, filename_completer); + + /* Deprecate the old version without "full" prefix. */ + c = add_alias_cmd ("restore", "full restore", class_obscure, 1, + &record_cmdlist); set_cmd_completer (c, filename_completer); + deprecate_cmd (c, "record full restore"); - add_cmd ("delete", class_obscure, cmd_record_delete, - _("Delete the rest of execution log and start recording it anew."), - &record_cmdlist); - add_alias_cmd ("d", "delete", class_obscure, 1, &record_cmdlist); - add_alias_cmd ("del", "delete", class_obscure, 1, &record_cmdlist); + add_prefix_cmd ("full", class_support, set_record_full_command, + _("Set record options"), &set_record_full_cmdlist, + "set record full ", 0, &set_record_cmdlist); - add_cmd ("stop", class_obscure, cmd_record_stop, - _("Stop the record/replay target."), - &record_cmdlist); - add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist); + add_prefix_cmd ("full", class_support, show_record_full_command, + _("Show record options"), &show_record_full_cmdlist, + "show record full ", 0, &show_record_cmdlist); /* Record instructions number limit command. */ add_setshow_boolean_cmd ("stop-at-limit", no_class, - &record_stop_at_limit, _("\ + &record_full_stop_at_limit, _("\ Set whether record/replay stops when record/replay buffer becomes full."), _("\ Show whether record/replay stops when record/replay buffer becomes full."), _("Default is ON.\n\ @@ -2938,23 +2964,36 @@ When ON, if the record/replay buffer becomes full, ask user what to do.\n\ When OFF, if the record/replay buffer becomes full,\n\ delete the oldest recorded instruction to make room for each new one."), NULL, NULL, - &set_record_cmdlist, &show_record_cmdlist); + &set_record_full_cmdlist, &show_record_full_cmdlist); + + c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", no_class, 1, + &set_record_cmdlist); + deprecate_cmd (c, "set record full stop-at-limit"); + + c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", no_class, 1, + &show_record_cmdlist); + deprecate_cmd (c, "show record full stop-at-limit"); + add_setshow_uinteger_cmd ("insn-number-max", no_class, - &record_insn_max_num, + &record_full_insn_max_num, _("Set record/replay buffer limit."), _("Show record/replay buffer limit."), _("\ Set the maximum number of instructions to be stored in the\n\ record/replay buffer. Zero means unlimited. Default is 200000."), - set_record_insn_max_num, - NULL, &set_record_cmdlist, &show_record_cmdlist); + set_record_full_insn_max_num, + NULL, &set_record_full_cmdlist, + &show_record_full_cmdlist); - add_cmd ("goto", class_obscure, cmd_record_goto, _("\ -Restore the program to its state at instruction number N.\n\ -Argument is instruction number, as shown by 'info record'."), - &record_cmdlist); + c = add_alias_cmd ("insn-number-max", "full insn-number-max", no_class, 1, + &set_record_cmdlist); + deprecate_cmd (c, "set record full insn-number-max"); + + c = add_alias_cmd ("insn-number-max", "full insn-number-max", no_class, 1, + &show_record_cmdlist); + deprecate_cmd (c, "show record full insn-number-max"); add_setshow_boolean_cmd ("memory-query", no_class, - &record_memory_query, _("\ + &record_full_memory_query, _("\ Set whether query if PREC cannot record memory change of next instruction."), _("\ Show whether query if PREC cannot record memory change of next instruction."), @@ -2962,6 +3001,14 @@ Show whether query if PREC cannot record memory change of next instruction."), Default is OFF.\n\ When ON, query if PREC cannot record memory change of next instruction."), NULL, NULL, - &set_record_cmdlist, &show_record_cmdlist); + &set_record_full_cmdlist, + &show_record_full_cmdlist); + + c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1, + &set_record_cmdlist); + deprecate_cmd (c, "set record full memory-query"); + c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1, + &show_record_cmdlist); + deprecate_cmd (c, "show record full memory-query"); } diff --git a/contrib/gdb-7/gdb/record.h b/contrib/gdb-7/gdb/record-full.h similarity index 60% copy from contrib/gdb-7/gdb/record.h copy to contrib/gdb-7/gdb/record-full.h index 84396e66cb..b5d5b314e9 100644 --- a/contrib/gdb-7/gdb/record.h +++ b/contrib/gdb-7/gdb/record-full.h @@ -1,6 +1,6 @@ /* Process record and replay target for GDB, the GNU debugger. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2013 Free Software Foundation, Inc. This file is part of GDB. @@ -17,17 +17,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef _RECORD_H_ -#define _RECORD_H_ +#ifndef RECORD_FULL_H +#define RECORD_FULL_H -#define RECORD_IS_USED (current_target.to_stratum == record_stratum) +extern int record_full_memory_query; -extern int record_debug; -extern int record_memory_query; +extern int record_full_arch_list_add_reg (struct regcache *regcache, int num); +extern int record_full_arch_list_add_mem (CORE_ADDR addr, int len); +extern int record_full_arch_list_add_end (void); +extern struct cleanup *record_full_gdb_operation_disable_set (void); -extern int record_arch_list_add_reg (struct regcache *regcache, int num); -extern int record_arch_list_add_mem (CORE_ADDR addr, int len); -extern int record_arch_list_add_end (void); -extern struct cleanup *record_gdb_operation_disable_set (void); - -#endif /* _RECORD_H_ */ +#endif /* RECORD_FULL_H */ diff --git a/contrib/gdb-7/gdb/record.c b/contrib/gdb-7/gdb/record.c index e396262a52..6bc1704a25 100644 --- a/contrib/gdb-7/gdb/record.c +++ b/contrib/gdb-7/gdb/record.c @@ -1,6 +1,6 @@ /* Process record and replay target for GDB, the GNU debugger. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -19,2092 +19,160 @@ #include "defs.h" #include "gdbcmd.h" -#include "regcache.h" -#include "gdbthread.h" -#include "event-top.h" -#include "exceptions.h" #include "completer.h" -#include "arch-utils.h" -#include "gdbcore.h" -#include "exec.h" #include "record.h" -#include "elf-bfd.h" -#include "gcore.h" -#include "event-loop.h" -#include "inf-loop.h" +#include "observer.h" +#include "inferior.h" +#include "common/common-utils.h" +#include "cli/cli-utils.h" +#include "disasm.h" -#include +#include -/* This module implements "target record", also known as "process - record and replay". This target sits on top of a "normal" target - (a target that "has execution"), and provides a record and replay - functionality, including reverse debugging. - - Target record has two modes: recording, and replaying. - - In record mode, we intercept the to_resume and to_wait methods. - Whenever gdb resumes the target, we run the target in single step - mode, and we build up an execution log in which, for each executed - instruction, we record all changes in memory and register state. - This is invisible to the user, to whom it just looks like an - ordinary debugging session (except for performance degredation). - - In replay mode, instead of actually letting the inferior run as a - process, we simulate its execution by playing back the recorded - execution log. For each instruction in the log, we simulate the - instruction's side effects by duplicating the changes that it would - have made on memory and registers. */ - -#define DEFAULT_RECORD_INSN_MAX_NUM 200000 - -#define RECORD_IS_REPLAY \ - (record_list->next || execution_direction == EXEC_REVERSE) - -#define RECORD_FILE_MAGIC netorder32(0x20091016) - -/* These are the core structs of the process record functionality. - - A record_entry is a record of the value change of a register - ("record_reg") or a part of memory ("record_mem"). And each - instruction must have a struct record_entry ("record_end") that - indicates that this is the last struct record_entry of this - instruction. - - Each struct record_entry is linked to "record_list" by "prev" and - "next" pointers. */ - -struct record_mem_entry -{ - CORE_ADDR addr; - int len; - /* Set this flag if target memory for this entry - can no longer be accessed. */ - int mem_entry_not_accessible; - union - { - gdb_byte *ptr; - gdb_byte buf[sizeof (gdb_byte *)]; - } u; -}; - -struct record_reg_entry -{ - unsigned short num; - unsigned short len; - union - { - gdb_byte *ptr; - gdb_byte buf[2 * sizeof (gdb_byte *)]; - } u; -}; - -struct record_end_entry -{ - enum target_signal sigval; - ULONGEST insn_num; -}; - -enum record_type -{ - record_end = 0, - record_reg, - record_mem -}; - -/* This is the data structure that makes up the execution log. - - The execution log consists of a single linked list of entries - of type "struct record_entry". It is doubly linked so that it - can be traversed in either direction. - - The start of the list is anchored by a struct called - "record_first". The pointer "record_list" either points to the - last entry that was added to the list (in record mode), or to the - next entry in the list that will be executed (in replay mode). - - Each list element (struct record_entry), in addition to next and - prev pointers, consists of a union of three entry types: mem, reg, - and end. A field called "type" determines which entry type is - represented by a given list element. - - Each instruction that is added to the execution log is represented - by a variable number of list elements ('entries'). The instruction - will have one "reg" entry for each register that is changed by - executing the instruction (including the PC in every case). It - will also have one "mem" entry for each memory change. Finally, - each instruction will have an "end" entry that separates it from - the changes associated with the next instruction. */ - -struct record_entry -{ - struct record_entry *prev; - struct record_entry *next; - enum record_type type; - union - { - /* reg */ - struct record_reg_entry reg; - /* mem */ - struct record_mem_entry mem; - /* end */ - struct record_end_entry end; - } u; -}; - -/* This is the debug switch for process record. */ -int record_debug = 0; - -/* If true, query if PREC cannot record memory - change of next instruction. */ -int record_memory_query = 0; - -struct record_core_buf_entry -{ - struct record_core_buf_entry *prev; - struct target_section *p; - bfd_byte *buf; -}; - -/* Record buf with core target. */ -static gdb_byte *record_core_regbuf = NULL; -static struct target_section *record_core_start; -static struct target_section *record_core_end; -static struct record_core_buf_entry *record_core_buf_list = NULL; - -/* The following variables are used for managing the linked list that - represents the execution log. - - record_first is the anchor that holds down the beginning of the list. - - record_list serves two functions: - 1) In record mode, it anchors the end of the list. - 2) In replay mode, it traverses the list and points to - the next instruction that must be emulated. - - record_arch_list_head and record_arch_list_tail are used to manage - a separate list, which is used to build up the change elements of - the currently executing instruction during record mode. When this - instruction has been completely annotated in the "arch list", it - will be appended to the main execution log. */ - -static struct record_entry record_first; -static struct record_entry *record_list = &record_first; -static struct record_entry *record_arch_list_head = NULL; -static struct record_entry *record_arch_list_tail = NULL; - -/* 1 ask user. 0 auto delete the last struct record_entry. */ -static int record_stop_at_limit = 1; -/* Maximum allowed number of insns in execution log. */ -static unsigned int record_insn_max_num = DEFAULT_RECORD_INSN_MAX_NUM; -/* Actual count of insns presently in execution log. */ -static int record_insn_num = 0; -/* Count of insns logged so far (may be larger - than count of insns presently in execution log). */ -static ULONGEST record_insn_count; - -/* The target_ops of process record. */ -static struct target_ops record_ops; -static struct target_ops record_core_ops; - -/* The beneath function pointers. */ -static struct target_ops *record_beneath_to_resume_ops; -static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int, - enum target_signal); -static struct target_ops *record_beneath_to_wait_ops; -static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t, - struct target_waitstatus *, - int); -static struct target_ops *record_beneath_to_store_registers_ops; -static void (*record_beneath_to_store_registers) (struct target_ops *, - struct regcache *, - int regno); -static struct target_ops *record_beneath_to_xfer_partial_ops; -static LONGEST (*record_beneath_to_xfer_partial) (struct target_ops *ops, - enum target_object object, - const char *annex, - gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, - LONGEST len); -static int (*record_beneath_to_insert_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*record_beneath_to_stopped_by_watchpoint) (void); -static int (*record_beneath_to_stopped_data_address) (struct target_ops *, - CORE_ADDR *); -static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *); - -/* Alloc and free functions for record_reg, record_mem, and record_end - entries. */ - -/* Alloc a record_reg record entry. */ - -static inline struct record_entry * -record_reg_alloc (struct regcache *regcache, int regnum) -{ - struct record_entry *rec; - struct gdbarch *gdbarch = get_regcache_arch (regcache); - - rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry)); - rec->type = record_reg; - rec->u.reg.num = regnum; - rec->u.reg.len = register_size (gdbarch, regnum); - if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) - rec->u.reg.u.ptr = (gdb_byte *) xmalloc (rec->u.reg.len); - - return rec; -} - -/* Free a record_reg record entry. */ - -static inline void -record_reg_release (struct record_entry *rec) -{ - gdb_assert (rec->type == record_reg); - if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) - xfree (rec->u.reg.u.ptr); - xfree (rec); -} - -/* Alloc a record_mem record entry. */ - -static inline struct record_entry * -record_mem_alloc (CORE_ADDR addr, int len) -{ - struct record_entry *rec; - - rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry)); - rec->type = record_mem; - rec->u.mem.addr = addr; - rec->u.mem.len = len; - if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) - rec->u.mem.u.ptr = (gdb_byte *) xmalloc (len); - - return rec; -} - -/* Free a record_mem record entry. */ - -static inline void -record_mem_release (struct record_entry *rec) -{ - gdb_assert (rec->type == record_mem); - if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) - xfree (rec->u.mem.u.ptr); - xfree (rec); -} - -/* Alloc a record_end record entry. */ - -static inline struct record_entry * -record_end_alloc (void) -{ - struct record_entry *rec; - - rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry)); - rec->type = record_end; - - return rec; -} - -/* Free a record_end record entry. */ - -static inline void -record_end_release (struct record_entry *rec) -{ - xfree (rec); -} - -/* Free one record entry, any type. - Return entry->type, in case caller wants to know. */ - -static inline enum record_type -record_entry_release (struct record_entry *rec) -{ - enum record_type type = rec->type; - - switch (type) { - case record_reg: - record_reg_release (rec); - break; - case record_mem: - record_mem_release (rec); - break; - case record_end: - record_end_release (rec); - break; - } - return type; -} - -/* Free all record entries in list pointed to by REC. */ - -static void -record_list_release (struct record_entry *rec) -{ - if (!rec) - return; - - while (rec->next) - rec = rec->next; - - while (rec->prev) - { - rec = rec->prev; - record_entry_release (rec->next); - } - - if (rec == &record_first) - { - record_insn_num = 0; - record_first.next = NULL; - } - else - record_entry_release (rec); -} - -/* Free all record entries forward of the given list position. */ - -static void -record_list_release_following (struct record_entry *rec) -{ - struct record_entry *tmp = rec->next; - - rec->next = NULL; - while (tmp) - { - rec = tmp->next; - if (record_entry_release (tmp) == record_end) - { - record_insn_num--; - record_insn_count--; - } - tmp = rec; - } -} - -/* Delete the first instruction from the beginning of the log, to make - room for adding a new instruction at the end of the log. - - Note -- this function does not modify record_insn_num. */ - -static void -record_list_release_first (void) -{ - struct record_entry *tmp; - - if (!record_first.next) - return; - - /* Loop until a record_end. */ - while (1) - { - /* Cut record_first.next out of the linked list. */ - tmp = record_first.next; - record_first.next = tmp->next; - tmp->next->prev = &record_first; - - /* tmp is now isolated, and can be deleted. */ - if (record_entry_release (tmp) == record_end) - break; /* End loop at first record_end. */ - - if (!record_first.next) - { - gdb_assert (record_insn_num == 1); - break; /* End loop when list is empty. */ - } - } -} - -/* Add a struct record_entry to record_arch_list. */ - -static void -record_arch_list_add (struct record_entry *rec) -{ - if (record_debug > 1) - fprintf_unfiltered (gdb_stdlog, - "Process record: record_arch_list_add %s.\n", - host_address_to_string (rec)); - - if (record_arch_list_tail) - { - record_arch_list_tail->next = rec; - rec->prev = record_arch_list_tail; - record_arch_list_tail = rec; - } - else - { - record_arch_list_head = rec; - record_arch_list_tail = rec; - } -} - -/* Return the value storage location of a record entry. */ -static inline gdb_byte * -record_get_loc (struct record_entry *rec) -{ - switch (rec->type) { - case record_mem: - if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) - return rec->u.mem.u.ptr; - else - return rec->u.mem.u.buf; - case record_reg: - if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) - return rec->u.reg.u.ptr; - else - return rec->u.reg.u.buf; - case record_end: - default: - gdb_assert_not_reached ("unexpected record_entry type"); - return NULL; - } -} - -/* Record the value of a register NUM to record_arch_list. */ - -int -record_arch_list_add_reg (struct regcache *regcache, int regnum) -{ - struct record_entry *rec; - - if (record_debug > 1) - fprintf_unfiltered (gdb_stdlog, - "Process record: add register num = %d to " - "record list.\n", - regnum); - - rec = record_reg_alloc (regcache, regnum); - - regcache_raw_read (regcache, regnum, record_get_loc (rec)); - - record_arch_list_add (rec); - - return 0; -} - -/* Record the value of a region of memory whose address is ADDR and - length is LEN to record_arch_list. */ - -int -record_arch_list_add_mem (CORE_ADDR addr, int len) -{ - struct record_entry *rec; - - if (record_debug > 1) - fprintf_unfiltered (gdb_stdlog, - "Process record: add mem addr = %s len = %d to " - "record list.\n", - paddress (target_gdbarch, addr), len); - - if (!addr) /* FIXME: Why? Some arch must permit it... */ - return 0; - - rec = record_mem_alloc (addr, len); - - if (target_read_memory (addr, record_get_loc (rec), len)) - { - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: error reading memory at " - "addr = %s len = %d.\n", - paddress (target_gdbarch, addr), len); - record_mem_release (rec); - return -1; - } - - record_arch_list_add (rec); - - return 0; -} - -/* Add a record_end type struct record_entry to record_arch_list. */ - -int -record_arch_list_add_end (void) -{ - struct record_entry *rec; - - if (record_debug > 1) - fprintf_unfiltered (gdb_stdlog, - "Process record: add end to arch list.\n"); - - rec = record_end_alloc (); - rec->u.end.sigval = TARGET_SIGNAL_0; - rec->u.end.insn_num = ++record_insn_count; - - record_arch_list_add (rec); - - return 0; -} - -static void -record_check_insn_num (int set_terminal) -{ - if (record_insn_max_num) - { - gdb_assert (record_insn_num <= record_insn_max_num); - if (record_insn_num == record_insn_max_num) - { - /* Ask user what to do. */ - if (record_stop_at_limit) - { - int q; - - if (set_terminal) - target_terminal_ours (); - q = yquery (_("Do you want to auto delete previous execution " - "log entries when record/replay buffer becomes " - "full (record stop-at-limit)?")); - if (set_terminal) - target_terminal_inferior (); - if (q) - record_stop_at_limit = 0; - else - error (_("Process record: stopped by user.")); - } - } - } -} - -static void -record_arch_list_cleanups (void *ignore) -{ - record_list_release (record_arch_list_tail); -} - -/* Before inferior step (when GDB record the running message, inferior - only can step), GDB will call this function to record the values to - record_list. This function will call gdbarch_process_record to - record the running message of inferior and set them to - record_arch_list, and add it to record_list. */ - -static int -record_message (struct regcache *regcache, enum target_signal signal) -{ - int ret; - struct gdbarch *gdbarch = get_regcache_arch (regcache); - struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups, 0); - - record_arch_list_head = NULL; - record_arch_list_tail = NULL; - - /* Check record_insn_num. */ - record_check_insn_num (1); - - /* If gdb sends a signal value to target_resume, - save it in the 'end' field of the previous instruction. - - Maybe process record should record what really happened, - rather than what gdb pretends has happened. - - So if Linux delivered the signal to the child process during - the record mode, we will record it and deliver it again in - the replay mode. - - If user says "ignore this signal" during the record mode, then - it will be ignored again during the replay mode (no matter if - the user says something different, like "deliver this signal" - during the replay mode). - - User should understand that nothing he does during the replay - mode will change the behavior of the child. If he tries, - then that is a user error. - - But we should still deliver the signal to gdb during the replay, - if we delivered it during the recording. Therefore we should - record the signal during record_wait, not record_resume. */ - if (record_list != &record_first) /* FIXME better way to check */ - { - gdb_assert (record_list->type == record_end); - record_list->u.end.sigval = signal; - } - - if (signal == TARGET_SIGNAL_0 - || !gdbarch_process_record_signal_p (gdbarch)) - ret = gdbarch_process_record (gdbarch, - regcache, - regcache_read_pc (regcache)); - else - ret = gdbarch_process_record_signal (gdbarch, - regcache, - signal); - - if (ret > 0) - error (_("Process record: inferior program stopped.")); - if (ret < 0) - error (_("Process record: failed to record execution log.")); - - discard_cleanups (old_cleanups); - - record_list->next = record_arch_list_head; - record_arch_list_head->prev = record_list; - record_list = record_arch_list_tail; - - if (record_insn_num == record_insn_max_num && record_insn_max_num) - record_list_release_first (); - else - record_insn_num++; - - return 1; -} - -struct record_message_args { - struct regcache *regcache; - enum target_signal signal; -}; - -static int -record_message_wrapper (void *args) -{ - struct record_message_args *record_args = args; - - return record_message (record_args->regcache, record_args->signal); -} - -static int -record_message_wrapper_safe (struct regcache *regcache, - enum target_signal signal) -{ - struct record_message_args args; - - args.regcache = regcache; - args.signal = signal; - - return catch_errors (record_message_wrapper, &args, NULL, RETURN_MASK_ALL); -} - -/* Set to 1 if record_store_registers and record_xfer_partial - doesn't need record. */ - -static int record_gdb_operation_disable = 0; - -struct cleanup * -record_gdb_operation_disable_set (void) -{ - struct cleanup *old_cleanups = NULL; - - old_cleanups = - make_cleanup_restore_integer (&record_gdb_operation_disable); - record_gdb_operation_disable = 1; - - return old_cleanups; -} - -/* Flag set to TRUE for target_stopped_by_watchpoint. */ -static int record_hw_watchpoint = 0; - -/* Execute one instruction from the record log. Each instruction in - the log will be represented by an arbitrary sequence of register - entries and memory entries, followed by an 'end' entry. */ - -static inline void -record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, - struct record_entry *entry) -{ - switch (entry->type) - { - case record_reg: /* reg */ - { - gdb_byte reg[MAX_REGISTER_SIZE]; - - if (record_debug > 1) - fprintf_unfiltered (gdb_stdlog, - "Process record: record_reg %s to " - "inferior num = %d.\n", - host_address_to_string (entry), - entry->u.reg.num); - - regcache_cooked_read (regcache, entry->u.reg.num, reg); - regcache_cooked_write (regcache, entry->u.reg.num, - record_get_loc (entry)); - memcpy (record_get_loc (entry), reg, entry->u.reg.len); - } - break; - - case record_mem: /* mem */ - { - /* Nothing to do if the entry is flagged not_accessible. */ - if (!entry->u.mem.mem_entry_not_accessible) - { - gdb_byte *mem = alloca (entry->u.mem.len); - - if (record_debug > 1) - fprintf_unfiltered (gdb_stdlog, - "Process record: record_mem %s to " - "inferior addr = %s len = %d.\n", - host_address_to_string (entry), - paddress (gdbarch, entry->u.mem.addr), - entry->u.mem.len); - - if (target_read_memory (entry->u.mem.addr, mem, entry->u.mem.len)) - { - entry->u.mem.mem_entry_not_accessible = 1; - if (record_debug) - warning (_("Process record: error reading memory at " - "addr = %s len = %d."), - paddress (gdbarch, entry->u.mem.addr), - entry->u.mem.len); - } - else - { - if (target_write_memory (entry->u.mem.addr, - record_get_loc (entry), - entry->u.mem.len)) - { - entry->u.mem.mem_entry_not_accessible = 1; - if (record_debug) - warning (_("Process record: error writing memory at " - "addr = %s len = %d."), - paddress (gdbarch, entry->u.mem.addr), - entry->u.mem.len); - } - else - { - memcpy (record_get_loc (entry), mem, entry->u.mem.len); - - /* We've changed memory --- check if a hardware - watchpoint should trap. Note that this - presently assumes the target beneath supports - continuable watchpoints. On non-continuable - watchpoints target, we'll want to check this - _before_ actually doing the memory change, and - not doing the change at all if the watchpoint - traps. */ - if (hardware_watchpoint_inserted_in_range - (get_regcache_aspace (regcache), - entry->u.mem.addr, entry->u.mem.len)) - record_hw_watchpoint = 1; - } - } - } - } - break; - } -} - -static struct target_ops *tmp_to_resume_ops; -static void (*tmp_to_resume) (struct target_ops *, ptid_t, int, - enum target_signal); -static struct target_ops *tmp_to_wait_ops; -static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t, - struct target_waitstatus *, - int); -static struct target_ops *tmp_to_store_registers_ops; -static void (*tmp_to_store_registers) (struct target_ops *, - struct regcache *, - int regno); -static struct target_ops *tmp_to_xfer_partial_ops; -static LONGEST (*tmp_to_xfer_partial) (struct target_ops *ops, - enum target_object object, - const char *annex, - gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, - LONGEST len); -static int (*tmp_to_insert_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*tmp_to_remove_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*tmp_to_stopped_by_watchpoint) (void); -static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *); -static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *); -static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *); - -static void record_restore (void); - -/* Asynchronous signal handle registered as event loop source for when - we have pending events ready to be passed to the core. */ - -static struct async_event_handler *record_async_inferior_event_token; - -static void -record_async_inferior_event_handler (gdb_client_data data) -{ - inferior_event_handler (INF_REG_EVENT, NULL); -} - -/* Open the process record target. */ - -static void -record_core_open_1 (char *name, int from_tty) -{ - struct regcache *regcache = get_current_regcache (); - int regnum = gdbarch_num_regs (get_regcache_arch (regcache)); - int i; - - /* Get record_core_regbuf. */ - target_fetch_registers (regcache, -1); - record_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum); - for (i = 0; i < regnum; i ++) - regcache_raw_collect (regcache, i, - record_core_regbuf + MAX_REGISTER_SIZE * i); - - /* Get record_core_start and record_core_end. */ - if (build_section_table (core_bfd, &record_core_start, &record_core_end)) - { - xfree (record_core_regbuf); - record_core_regbuf = NULL; - error (_("\"%s\": Can't find sections: %s"), - bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ())); - } - - push_target (&record_core_ops); - record_restore (); -} - -/* "to_open" target method for 'live' processes. */ - -static void -record_open_1 (char *name, int from_tty) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n"); - - /* check exec */ - if (!target_has_execution) - error (_("Process record: the program is not being run.")); - if (non_stop) - error (_("Process record target can't debug inferior in non-stop mode " - "(non-stop).")); - - if (!gdbarch_process_record_p (target_gdbarch)) - error (_("Process record: the current architecture doesn't support " - "record function.")); - - if (!tmp_to_resume) - error (_("Could not find 'to_resume' method on the target stack.")); - if (!tmp_to_wait) - error (_("Could not find 'to_wait' method on the target stack.")); - if (!tmp_to_store_registers) - error (_("Could not find 'to_store_registers' " - "method on the target stack.")); - if (!tmp_to_insert_breakpoint) - error (_("Could not find 'to_insert_breakpoint' " - "method on the target stack.")); - if (!tmp_to_remove_breakpoint) - error (_("Could not find 'to_remove_breakpoint' " - "method on the target stack.")); - if (!tmp_to_stopped_by_watchpoint) - error (_("Could not find 'to_stopped_by_watchpoint' " - "method on the target stack.")); - if (!tmp_to_stopped_data_address) - error (_("Could not find 'to_stopped_data_address' " - "method on the target stack.")); - - push_target (&record_ops); -} - -/* "to_open" target method. Open the process record target. */ - -static void -record_open (char *name, int from_tty) -{ - struct target_ops *t; - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n"); - - /* Check if record target is already running. */ - if (current_target.to_stratum == record_stratum) - error (_("Process record target already running. Use \"record stop\" to " - "stop record target first.")); - - /* Reset the tmp beneath pointers. */ - tmp_to_resume_ops = NULL; - tmp_to_resume = NULL; - tmp_to_wait_ops = NULL; - tmp_to_wait = NULL; - tmp_to_store_registers_ops = NULL; - tmp_to_store_registers = NULL; - tmp_to_xfer_partial_ops = NULL; - tmp_to_xfer_partial = NULL; - tmp_to_insert_breakpoint = NULL; - tmp_to_remove_breakpoint = NULL; - tmp_to_stopped_by_watchpoint = NULL; - tmp_to_stopped_data_address = NULL; - tmp_to_async = NULL; - - /* Set the beneath function pointers. */ - for (t = current_target.beneath; t != NULL; t = t->beneath) - { - if (!tmp_to_resume) - { - tmp_to_resume = t->to_resume; - tmp_to_resume_ops = t; - } - if (!tmp_to_wait) - { - tmp_to_wait = t->to_wait; - tmp_to_wait_ops = t; - } - if (!tmp_to_store_registers) - { - tmp_to_store_registers = t->to_store_registers; - tmp_to_store_registers_ops = t; - } - if (!tmp_to_xfer_partial) - { - tmp_to_xfer_partial = t->to_xfer_partial; - tmp_to_xfer_partial_ops = t; - } - if (!tmp_to_insert_breakpoint) - tmp_to_insert_breakpoint = t->to_insert_breakpoint; - if (!tmp_to_remove_breakpoint) - tmp_to_remove_breakpoint = t->to_remove_breakpoint; - if (!tmp_to_stopped_by_watchpoint) - tmp_to_stopped_by_watchpoint = t->to_stopped_by_watchpoint; - if (!tmp_to_stopped_data_address) - tmp_to_stopped_data_address = t->to_stopped_data_address; - if (!tmp_to_async) - tmp_to_async = t->to_async; - } - if (!tmp_to_xfer_partial) - error (_("Could not find 'to_xfer_partial' method on the target stack.")); - - /* Reset */ - record_insn_num = 0; - record_insn_count = 0; - record_list = &record_first; - record_list->next = NULL; - - /* Set the tmp beneath pointers to beneath pointers. */ - record_beneath_to_resume_ops = tmp_to_resume_ops; - record_beneath_to_resume = tmp_to_resume; - record_beneath_to_wait_ops = tmp_to_wait_ops; - record_beneath_to_wait = tmp_to_wait; - record_beneath_to_store_registers_ops = tmp_to_store_registers_ops; - record_beneath_to_store_registers = tmp_to_store_registers; - record_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops; - record_beneath_to_xfer_partial = tmp_to_xfer_partial; - record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint; - record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint; - record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint; - record_beneath_to_stopped_data_address = tmp_to_stopped_data_address; - record_beneath_to_async = tmp_to_async; - - if (core_bfd) - record_core_open_1 (name, from_tty); - else - record_open_1 (name, from_tty); - - /* Register extra event sources in the event loop. */ - record_async_inferior_event_token - = create_async_event_handler (record_async_inferior_event_handler, - NULL); -} - -/* "to_close" target method. Close the process record target. */ - -static void -record_close (int quitting) -{ - struct record_core_buf_entry *entry; - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n"); - - record_list_release (record_list); - - /* Release record_core_regbuf. */ - if (record_core_regbuf) - { - xfree (record_core_regbuf); - record_core_regbuf = NULL; - } - - /* Release record_core_buf_list. */ - if (record_core_buf_list) - { - for (entry = record_core_buf_list->prev; entry; entry = entry->prev) - { - xfree (record_core_buf_list); - record_core_buf_list = entry; - } - record_core_buf_list = NULL; - } - - if (record_async_inferior_event_token) - delete_async_event_handler (&record_async_inferior_event_token); -} - -static int record_resume_step = 0; - -/* True if we've been resumed, and so each record_wait call should - advance execution. If this is false, record_wait will return a - TARGET_WAITKIND_IGNORE. */ -static int record_resumed = 0; - -/* The execution direction of the last resume we got. This is - necessary for async mode. Vis (order is not strictly accurate): - - 1. user has the global execution direction set to forward - 2. user does a reverse-step command - 3. record_resume is called with global execution direction - temporarily switched to reverse - 4. GDB's execution direction is reverted back to forward - 5. target record notifies event loop there's an event to handle - 6. infrun asks the target which direction was it going, and switches - the global execution direction accordingly (to reverse) - 7. infrun polls an event out of the record target, and handles it - 8. GDB goes back to the event loop, and goto #4. -*/ -static enum exec_direction_kind record_execution_dir = EXEC_FORWARD; - -/* "to_resume" target method. Resume the process record target. */ - -static void -record_resume (struct target_ops *ops, ptid_t ptid, int step, - enum target_signal signal) -{ - record_resume_step = step; - record_resumed = 1; - record_execution_dir = execution_direction; - - if (!RECORD_IS_REPLAY) - { - struct gdbarch *gdbarch = target_thread_architecture (ptid); - - record_message (get_current_regcache (), signal); - - if (!step) - { - /* This is not hard single step. */ - if (!gdbarch_software_single_step_p (gdbarch)) - { - /* This is a normal continue. */ - step = 1; - } - else - { - /* This arch support soft sigle step. */ - if (single_step_breakpoints_inserted ()) - { - /* This is a soft single step. */ - record_resume_step = 1; - } - else - { - /* This is a continue. - Try to insert a soft single step breakpoint. */ - if (!gdbarch_software_single_step (gdbarch, - get_current_frame ())) - { - /* This system don't want use soft single step. - Use hard sigle step. */ - step = 1; - } - } - } - } - - record_beneath_to_resume (record_beneath_to_resume_ops, - ptid, step, signal); - } - - /* We are about to start executing the inferior (or simulate it), - let's register it with the event loop. */ - if (target_can_async_p ()) - { - target_async (inferior_event_handler, 0); - /* Notify the event loop there's an event to wait for. We do - most of the work in record_wait. */ - mark_async_event_handler (record_async_inferior_event_token); - } -} - -static int record_get_sig = 0; - -/* SIGINT signal handler, registered by "to_wait" method. */ - -static void -record_sig_handler (int signo) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: get a signal\n"); - - /* It will break the running inferior in replay mode. */ - record_resume_step = 1; - - /* It will let record_wait set inferior status to get the signal - SIGINT. */ - record_get_sig = 1; -} - -static void -record_wait_cleanups (void *ignore) -{ - if (execution_direction == EXEC_REVERSE) - { - if (record_list->next) - record_list = record_list->next; - } - else - record_list = record_list->prev; -} - -/* "to_wait" target method for process record target. - - In record mode, the target is always run in singlestep mode - (even when gdb says to continue). The to_wait method intercepts - the stop events and determines which ones are to be passed on to - gdb. Most stop events are just singlestep events that gdb is not - to know about, so the to_wait method just records them and keeps - singlestepping. - - In replay mode, this function emulates the recorded execution log, - one instruction at a time (forward or backward), and determines - where to stop. */ - -static ptid_t -record_wait_1 (struct target_ops *ops, - ptid_t ptid, struct target_waitstatus *status, - int options) -{ - struct cleanup *set_cleanups = record_gdb_operation_disable_set (); - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: record_wait " - "record_resume_step = %d, record_resumed = %d, direction=%s\n", - record_resume_step, record_resumed, - record_execution_dir == EXEC_FORWARD ? "forward" : "reverse"); - - if (!record_resumed) - { - gdb_assert ((options & TARGET_WNOHANG) != 0); - - /* No interesting event. */ - status->kind = TARGET_WAITKIND_IGNORE; - return minus_one_ptid; - } - - record_get_sig = 0; - signal (SIGINT, record_sig_handler); - - if (!RECORD_IS_REPLAY && ops != &record_core_ops) - { - if (record_resume_step) - { - /* This is a single step. */ - return record_beneath_to_wait (record_beneath_to_wait_ops, - ptid, status, options); - } - else - { - /* This is not a single step. */ - ptid_t ret; - CORE_ADDR tmp_pc; - struct gdbarch *gdbarch = target_thread_architecture (inferior_ptid); - - while (1) - { - ret = record_beneath_to_wait (record_beneath_to_wait_ops, - ptid, status, options); - if (status->kind == TARGET_WAITKIND_IGNORE) - { - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: record_wait " - "target beneath not done yet\n"); - return ret; - } - - if (single_step_breakpoints_inserted ()) - remove_single_step_breakpoints (); - - if (record_resume_step) - return ret; - - /* Is this a SIGTRAP? */ - if (status->kind == TARGET_WAITKIND_STOPPED - && status->value.sig == TARGET_SIGNAL_TRAP) - { - struct regcache *regcache; - struct address_space *aspace; - - /* Yes -- this is likely our single-step finishing, - but check if there's any reason the core would be - interested in the event. */ - - registers_changed (); - regcache = get_current_regcache (); - tmp_pc = regcache_read_pc (regcache); - aspace = get_regcache_aspace (regcache); - - if (target_stopped_by_watchpoint ()) - { - /* Always interested in watchpoints. */ - } - else if (breakpoint_inserted_here_p (aspace, tmp_pc)) - { - /* There is a breakpoint here. Let the core - handle it. */ - if (software_breakpoint_inserted_here_p (aspace, tmp_pc)) - { - struct gdbarch *gdbarch - = get_regcache_arch (regcache); - CORE_ADDR decr_pc_after_break - = gdbarch_decr_pc_after_break (gdbarch); - if (decr_pc_after_break) - regcache_write_pc (regcache, - tmp_pc + decr_pc_after_break); - } - } - else - { - /* This is a single-step trap. Record the - insn and issue another step. - FIXME: this part can be a random SIGTRAP too. - But GDB cannot handle it. */ - int step = 1; - - if (!record_message_wrapper_safe (regcache, - TARGET_SIGNAL_0)) - { - status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = TARGET_SIGNAL_0; - break; - } - - if (gdbarch_software_single_step_p (gdbarch)) - { - /* Try to insert the software single step breakpoint. - If insert success, set step to 0. */ - set_executing (inferior_ptid, 0); - reinit_frame_cache (); - if (gdbarch_software_single_step (gdbarch, - get_current_frame ())) - step = 0; - set_executing (inferior_ptid, 1); - } - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: record_wait " - "issuing one more step in the target beneath\n"); - record_beneath_to_resume (record_beneath_to_resume_ops, - ptid, step, - TARGET_SIGNAL_0); - continue; - } - } - - /* The inferior is broken by a breakpoint or a signal. */ - break; - } - - return ret; - } - } - else - { - struct regcache *regcache = get_current_regcache (); - struct gdbarch *gdbarch = get_regcache_arch (regcache); - struct address_space *aspace = get_regcache_aspace (regcache); - int continue_flag = 1; - int first_record_end = 1; - struct cleanup *old_cleanups = make_cleanup (record_wait_cleanups, 0); - CORE_ADDR tmp_pc; - - record_hw_watchpoint = 0; - status->kind = TARGET_WAITKIND_STOPPED; - - /* Check breakpoint when forward execute. */ - if (execution_direction == EXEC_FORWARD) - { - tmp_pc = regcache_read_pc (regcache); - if (breakpoint_inserted_here_p (aspace, tmp_pc)) - { - int decr_pc_after_break = gdbarch_decr_pc_after_break (gdbarch); - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: break at %s.\n", - paddress (gdbarch, tmp_pc)); - - if (decr_pc_after_break - && !record_resume_step - && software_breakpoint_inserted_here_p (aspace, tmp_pc)) - regcache_write_pc (regcache, - tmp_pc + decr_pc_after_break); - goto replay_out; - } - } - - /* If GDB is in terminal_inferior mode, it will not get the signal. - And in GDB replay mode, GDB doesn't need to be in terminal_inferior - mode, because inferior will not executed. - Then set it to terminal_ours to make GDB get the signal. */ - target_terminal_ours (); - - /* In EXEC_FORWARD mode, record_list points to the tail of prev - instruction. */ - if (execution_direction == EXEC_FORWARD && record_list->next) - record_list = record_list->next; - - /* Loop over the record_list, looking for the next place to - stop. */ - do - { - /* Check for beginning and end of log. */ - if (execution_direction == EXEC_REVERSE - && record_list == &record_first) - { - /* Hit beginning of record log in reverse. */ - status->kind = TARGET_WAITKIND_NO_HISTORY; - break; - } - if (execution_direction != EXEC_REVERSE && !record_list->next) - { - /* Hit end of record log going forward. */ - status->kind = TARGET_WAITKIND_NO_HISTORY; - break; - } - - record_exec_insn (regcache, gdbarch, record_list); - - if (record_list->type == record_end) - { - if (record_debug > 1) - fprintf_unfiltered (gdb_stdlog, - "Process record: record_end %s to " - "inferior.\n", - host_address_to_string (record_list)); - - if (first_record_end && execution_direction == EXEC_REVERSE) - { - /* When reverse excute, the first record_end is the part of - current instruction. */ - first_record_end = 0; - } - else - { - /* In EXEC_REVERSE mode, this is the record_end of prev - instruction. - In EXEC_FORWARD mode, this is the record_end of current - instruction. */ - /* step */ - if (record_resume_step) - { - if (record_debug > 1) - fprintf_unfiltered (gdb_stdlog, - "Process record: step.\n"); - continue_flag = 0; - } - - /* check breakpoint */ - tmp_pc = regcache_read_pc (regcache); - if (breakpoint_inserted_here_p (aspace, tmp_pc)) - { - int decr_pc_after_break - = gdbarch_decr_pc_after_break (gdbarch); - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: break " - "at %s.\n", - paddress (gdbarch, tmp_pc)); - if (decr_pc_after_break - && execution_direction == EXEC_FORWARD - && !record_resume_step - && software_breakpoint_inserted_here_p (aspace, - tmp_pc)) - regcache_write_pc (regcache, - tmp_pc + decr_pc_after_break); - continue_flag = 0; - } - - if (record_hw_watchpoint) - { - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: hit hw " - "watchpoint.\n"); - continue_flag = 0; - } - /* Check target signal */ - if (record_list->u.end.sigval != TARGET_SIGNAL_0) - /* FIXME: better way to check */ - continue_flag = 0; - } - } - - if (continue_flag) - { - if (execution_direction == EXEC_REVERSE) - { - if (record_list->prev) - record_list = record_list->prev; - } - else - { - if (record_list->next) - record_list = record_list->next; - } - } - } - while (continue_flag); - -replay_out: - if (record_get_sig) - status->value.sig = TARGET_SIGNAL_INT; - else if (record_list->u.end.sigval != TARGET_SIGNAL_0) - /* FIXME: better way to check */ - status->value.sig = record_list->u.end.sigval; - else - status->value.sig = TARGET_SIGNAL_TRAP; - - discard_cleanups (old_cleanups); - } - - signal (SIGINT, handle_sigint); - - do_cleanups (set_cleanups); - return inferior_ptid; -} - -static ptid_t -record_wait (struct target_ops *ops, - ptid_t ptid, struct target_waitstatus *status, - int options) -{ - ptid_t return_ptid; - - return_ptid = record_wait_1 (ops, ptid, status, options); - if (status->kind != TARGET_WAITKIND_IGNORE) - { - /* We're reporting a stop. Make sure any spurious - target_wait(WNOHANG) doesn't advance the target until the - core wants us resumed again. */ - record_resumed = 0; - } - return return_ptid; -} - -static int -record_stopped_by_watchpoint (void) -{ - if (RECORD_IS_REPLAY) - return record_hw_watchpoint; - else - return record_beneath_to_stopped_by_watchpoint (); -} - -static int -record_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) -{ - if (RECORD_IS_REPLAY) - return 0; - else - return record_beneath_to_stopped_data_address (ops, addr_p); -} - -/* "to_disconnect" method for process record target. */ - -static void -record_disconnect (struct target_ops *target, char *args, int from_tty) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_disconnect\n"); - - unpush_target (&record_ops); - target_disconnect (args, from_tty); -} - -/* "to_detach" method for process record target. */ - -static void -record_detach (struct target_ops *ops, char *args, int from_tty) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_detach\n"); - - unpush_target (&record_ops); - target_detach (args, from_tty); -} - -/* "to_mourn_inferior" method for process record target. */ - -static void -record_mourn_inferior (struct target_ops *ops) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: " - "record_mourn_inferior\n"); - - unpush_target (&record_ops); - target_mourn_inferior (); -} - -/* Close process record target before killing the inferior process. */ - -static void -record_kill (struct target_ops *ops) -{ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n"); - - unpush_target (&record_ops); - target_kill (); -} - -/* Record registers change (by user or by GDB) to list as an instruction. */ - -static void -record_registers_change (struct regcache *regcache, int regnum) -{ - /* Check record_insn_num. */ - record_check_insn_num (0); - - record_arch_list_head = NULL; - record_arch_list_tail = NULL; - - if (regnum < 0) - { - int i; - - for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++) - { - if (record_arch_list_add_reg (regcache, i)) - { - record_list_release (record_arch_list_tail); - error (_("Process record: failed to record execution log.")); - } - } - } - else - { - if (record_arch_list_add_reg (regcache, regnum)) - { - record_list_release (record_arch_list_tail); - error (_("Process record: failed to record execution log.")); - } - } - if (record_arch_list_add_end ()) - { - record_list_release (record_arch_list_tail); - error (_("Process record: failed to record execution log.")); - } - record_list->next = record_arch_list_head; - record_arch_list_head->prev = record_list; - record_list = record_arch_list_tail; - - if (record_insn_num == record_insn_max_num && record_insn_max_num) - record_list_release_first (); - else - record_insn_num++; -} - -/* "to_store_registers" method for process record target. */ - -static void -record_store_registers (struct target_ops *ops, struct regcache *regcache, - int regno) -{ - if (!record_gdb_operation_disable) - { - if (RECORD_IS_REPLAY) - { - int n; - - /* Let user choose if he wants to write register or not. */ - if (regno < 0) - n = - query (_("Because GDB is in replay mode, changing the " - "value of a register will make the execution " - "log unusable from this point onward. " - "Change all registers?")); - else - n = - query (_("Because GDB is in replay mode, changing the value " - "of a register will make the execution log unusable " - "from this point onward. Change register %s?"), - gdbarch_register_name (get_regcache_arch (regcache), - regno)); - - if (!n) - { - /* Invalidate the value of regcache that was set in function - "regcache_raw_write". */ - if (regno < 0) - { - int i; - - for (i = 0; - i < gdbarch_num_regs (get_regcache_arch (regcache)); - i++) - regcache_invalidate (regcache, i); - } - else - regcache_invalidate (regcache, regno); - - error (_("Process record canceled the operation.")); - } - - /* Destroy the record from here forward. */ - record_list_release_following (record_list); - } - - record_registers_change (regcache, regno); - } - record_beneath_to_store_registers (record_beneath_to_store_registers_ops, - regcache, regno); -} - -/* "to_xfer_partial" method. Behavior is conditional on RECORD_IS_REPLAY. - In replay mode, we cannot write memory unles we are willing to - invalidate the record/replay log from this point forward. */ - -static LONGEST -record_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) -{ - if (!record_gdb_operation_disable - && (object == TARGET_OBJECT_MEMORY - || object == TARGET_OBJECT_RAW_MEMORY) && writebuf) - { - if (RECORD_IS_REPLAY) - { - /* Let user choose if he wants to write memory or not. */ - if (!query (_("Because GDB is in replay mode, writing to memory " - "will make the execution log unusable from this " - "point onward. Write memory at address %s?"), - paddress (target_gdbarch, offset))) - error (_("Process record canceled the operation.")); - - /* Destroy the record from here forward. */ - record_list_release_following (record_list); - } - - /* Check record_insn_num */ - record_check_insn_num (0); - - /* Record registers change to list as an instruction. */ - record_arch_list_head = NULL; - record_arch_list_tail = NULL; - if (record_arch_list_add_mem (offset, len)) - { - record_list_release (record_arch_list_tail); - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: failed to record " - "execution log."); - return -1; - } - if (record_arch_list_add_end ()) - { - record_list_release (record_arch_list_tail); - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "Process record: failed to record " - "execution log."); - return -1; - } - record_list->next = record_arch_list_head; - record_arch_list_head->prev = record_list; - record_list = record_arch_list_tail; - - if (record_insn_num == record_insn_max_num && record_insn_max_num) - record_list_release_first (); - else - record_insn_num++; - } - - return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops, - object, annex, readbuf, writebuf, - offset, len); -} - -/* Behavior is conditional on RECORD_IS_REPLAY. - We will not actually insert or remove breakpoints when replaying, - nor when recording. */ - -static int -record_insert_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) -{ - if (!RECORD_IS_REPLAY) - { - struct cleanup *old_cleanups = record_gdb_operation_disable_set (); - int ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt); - - do_cleanups (old_cleanups); - - return ret; - } - - return 0; -} - -/* "to_remove_breakpoint" method for process record target. */ - -static int -record_remove_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) -{ - if (!RECORD_IS_REPLAY) - { - struct cleanup *old_cleanups = record_gdb_operation_disable_set (); - int ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt); - - do_cleanups (old_cleanups); - - return ret; - } - - return 0; -} - -/* "to_can_execute_reverse" method for process record target. */ - -static int -record_can_execute_reverse (void) -{ - return 1; -} - -/* "to_get_bookmark" method for process record and prec over core. */ +/* This is the debug switch for process record. */ +unsigned int record_debug = 0; -static gdb_byte * -record_get_bookmark (char *args, int from_tty) -{ - gdb_byte *ret = NULL; +/* The number of instructions to print in "record instruction-history". */ +static unsigned int record_insn_history_size = 10; - /* Return stringified form of instruction count. */ - if (record_list && record_list->type == record_end) - ret = xstrdup (pulongest (record_list->u.end.insn_num)); +/* The number of functions to print in "record function-call-history". */ +static unsigned int record_call_history_size = 10; - if (record_debug) - { - if (ret) - fprintf_unfiltered (gdb_stdlog, - "record_get_bookmark returns %s\n", ret); - else - fprintf_unfiltered (gdb_stdlog, - "record_get_bookmark returns NULL\n"); - } - return ret; -} +struct cmd_list_element *record_cmdlist = NULL; +struct cmd_list_element *set_record_cmdlist = NULL; +struct cmd_list_element *show_record_cmdlist = NULL; +struct cmd_list_element *info_record_cmdlist = NULL; -/* The implementation of the command "record goto". */ -static void cmd_record_goto (char *, int); +#define DEBUG(msg, args...) \ + if (record_debug) \ + fprintf_unfiltered (gdb_stdlog, "record: " msg "\n", ##args) -/* "to_goto_bookmark" method for process record and prec over core. */ +/* Find the record target in the target stack. */ -static void -record_goto_bookmark (gdb_byte *bookmark, int from_tty) +static struct target_ops * +find_record_target (void) { - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - "record_goto_bookmark receives %s\n", bookmark); - - if (bookmark[0] == '\'' || bookmark[0] == '\"') - { - if (bookmark[strlen (bookmark) - 1] != bookmark[0]) - error (_("Unbalanced quotes: %s"), bookmark); - - /* Strip trailing quote. */ - bookmark[strlen (bookmark) - 1] = '\0'; - /* Strip leading quote. */ - bookmark++; - /* Pass along to cmd_record_goto. */ - } + struct target_ops *t; - cmd_record_goto ((char *) bookmark, from_tty); - return; -} + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_stratum == record_stratum) + return t; -static void -record_async (void (*callback) (enum inferior_event_type event_type, - void *context), void *context) -{ - /* If we're on top of a line target (e.g., linux-nat, remote), then - set it to async mode as well. Will be NULL if we're sitting on - top of the core target, for "record restore". */ - if (record_beneath_to_async != NULL) - record_beneath_to_async (callback, context); + return NULL; } -static int -record_can_async_p (void) -{ - /* We only enable async when the user specifically asks for it. */ - return target_async_permitted; -} +/* Check that recording is active. Throw an error, if it isn't. */ -static int -record_is_async_p (void) +static struct target_ops * +require_record_target (void) { - /* We only enable async when the user specifically asks for it. */ - return target_async_permitted; -} + struct target_ops *t; -static enum exec_direction_kind -record_execution_direction (void) -{ - return record_execution_dir; -} + t = find_record_target (); + if (t == NULL) + error (_("No record target is currently active.\n" + "Use one of the \"target record-\" commands first.")); -static void -init_record_ops (void) -{ - record_ops.to_shortname = "record"; - record_ops.to_longname = "Process record and replay target"; - record_ops.to_doc = - "Log program while executing and replay execution from log."; - record_ops.to_open = record_open; - record_ops.to_close = record_close; - record_ops.to_resume = record_resume; - record_ops.to_wait = record_wait; - record_ops.to_disconnect = record_disconnect; - record_ops.to_detach = record_detach; - record_ops.to_mourn_inferior = record_mourn_inferior; - record_ops.to_kill = record_kill; - record_ops.to_create_inferior = find_default_create_inferior; - record_ops.to_store_registers = record_store_registers; - record_ops.to_xfer_partial = record_xfer_partial; - record_ops.to_insert_breakpoint = record_insert_breakpoint; - record_ops.to_remove_breakpoint = record_remove_breakpoint; - record_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint; - record_ops.to_stopped_data_address = record_stopped_data_address; - record_ops.to_can_execute_reverse = record_can_execute_reverse; - record_ops.to_stratum = record_stratum; - /* Add bookmark target methods. */ - record_ops.to_get_bookmark = record_get_bookmark; - record_ops.to_goto_bookmark = record_goto_bookmark; - record_ops.to_async = record_async; - record_ops.to_can_async_p = record_can_async_p; - record_ops.to_is_async_p = record_is_async_p; - record_ops.to_execution_direction = record_execution_direction; - record_ops.to_magic = OPS_MAGIC; + return t; } -/* "to_resume" method for prec over corefile. */ +/* See record.h. */ -static void -record_core_resume (struct target_ops *ops, ptid_t ptid, int step, - enum target_signal signal) +int +record_read_memory (struct gdbarch *gdbarch, + CORE_ADDR memaddr, gdb_byte *myaddr, + ssize_t len) { - record_resume_step = step; - record_resumed = 1; - record_execution_dir = execution_direction; + int ret = target_read_memory (memaddr, myaddr, len); - /* We are about to start executing the inferior (or simulate it), - let's register it with the event loop. */ - if (target_can_async_p ()) - { - target_async (inferior_event_handler, 0); + if (ret != 0) + DEBUG ("error reading memory at addr %s len = %ld.\n", + paddress (gdbarch, memaddr), (long) len); - /* Notify the event loop there's an event to wait for. */ - mark_async_event_handler (record_async_inferior_event_token); - } + return ret; } -/* "to_kill" method for prec over corefile. */ +/* Stop recording. */ static void -record_core_kill (struct target_ops *ops) +record_stop (struct target_ops *t) { - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Process record: record_core_kill\n"); + DEBUG ("stop %s", t->to_shortname); - unpush_target (&record_core_ops); + if (t->to_stop_recording != NULL) + t->to_stop_recording (); } -/* "to_fetch_registers" method for prec over corefile. */ +/* Unpush the record target. */ static void -record_core_fetch_registers (struct target_ops *ops, - struct regcache *regcache, - int regno) +record_unpush (struct target_ops *t) { - if (regno < 0) - { - int num = gdbarch_num_regs (get_regcache_arch (regcache)); - int i; + DEBUG ("unpush %s", t->to_shortname); - for (i = 0; i < num; i ++) - regcache_raw_supply (regcache, i, - record_core_regbuf + MAX_REGISTER_SIZE * i); - } - else - regcache_raw_supply (regcache, regno, - record_core_regbuf + MAX_REGISTER_SIZE * regno); + unpush_target (t); } -/* "to_prepare_to_store" method for prec over corefile. */ +/* See record.h. */ -static void -record_core_prepare_to_store (struct regcache *regcache) +void +record_disconnect (struct target_ops *t, char *args, int from_tty) { -} + gdb_assert (t->to_stratum == record_stratum); -/* "to_store_registers" method for prec over corefile. */ + DEBUG ("disconnect %s", t->to_shortname); -static void -record_core_store_registers (struct target_ops *ops, - struct regcache *regcache, - int regno) -{ - if (record_gdb_operation_disable) - regcache_raw_collect (regcache, regno, - record_core_regbuf + MAX_REGISTER_SIZE * regno); - else - error (_("You can't do that without a process to debug.")); + record_stop (t); + record_unpush (t); + + target_disconnect (args, from_tty); } -/* "to_xfer_partial" method for prec over corefile. */ +/* See record.h. */ -static LONGEST -record_core_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, - LONGEST len) +void +record_detach (struct target_ops *t, char *args, int from_tty) { - if (object == TARGET_OBJECT_MEMORY) - { - if (record_gdb_operation_disable || !writebuf) - { - struct target_section *p; + gdb_assert (t->to_stratum == record_stratum); - for (p = record_core_start; p < record_core_end; p++) - { - if (offset >= p->addr) - { - struct record_core_buf_entry *entry; - ULONGEST sec_offset; - - if (offset >= p->endaddr) - continue; - - if (offset + len > p->endaddr) - len = p->endaddr - offset; - - sec_offset = offset - p->addr; - - /* Read readbuf or write writebuf p, offset, len. */ - /* Check flags. */ - if (p->the_bfd_section->flags & SEC_CONSTRUCTOR - || (p->the_bfd_section->flags & SEC_HAS_CONTENTS) == 0) - { - if (readbuf) - memset (readbuf, 0, len); - return len; - } - /* Get record_core_buf_entry. */ - for (entry = record_core_buf_list; entry; - entry = entry->prev) - if (entry->p == p) - break; - if (writebuf) - { - if (!entry) - { - /* Add a new entry. */ - entry = (struct record_core_buf_entry *) - xmalloc (sizeof (struct record_core_buf_entry)); - entry->p = p; - if (!bfd_malloc_and_get_section (p->bfd, - p->the_bfd_section, - &entry->buf)) - { - xfree (entry); - return 0; - } - entry->prev = record_core_buf_list; - record_core_buf_list = entry; - } - - memcpy (entry->buf + sec_offset, writebuf, - (size_t) len); - } - else - { - if (!entry) - return record_beneath_to_xfer_partial - (record_beneath_to_xfer_partial_ops, - object, annex, readbuf, writebuf, - offset, len); - - memcpy (readbuf, entry->buf + sec_offset, - (size_t) len); - } - - return len; - } - } + DEBUG ("detach %s", t->to_shortname); - return -1; - } - else - error (_("You can't do that without a process to debug.")); - } + record_stop (t); + record_unpush (t); - return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops, - object, annex, readbuf, writebuf, - offset, len); + target_detach (args, from_tty); } -/* "to_insert_breakpoint" method for prec over corefile. */ +/* See record.h. */ -static int -record_core_insert_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) +void +record_mourn_inferior (struct target_ops *t) { - return 0; -} + gdb_assert (t->to_stratum == record_stratum); -/* "to_remove_breakpoint" method for prec over corefile. */ + DEBUG ("mourn inferior %s", t->to_shortname); -static int -record_core_remove_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) -{ - return 0; + /* It is safer to not stop recording. Resources will be freed when + threads are discarded. */ + record_unpush (t); + + target_mourn_inferior (); } -/* "to_has_execution" method for prec over corefile. */ +/* See record.h. */ -static int -record_core_has_execution (struct target_ops *ops, ptid_t the_ptid) +void +record_kill (struct target_ops *t) { - return 1; -} + gdb_assert (t->to_stratum == record_stratum); -static void -init_record_core_ops (void) -{ - record_core_ops.to_shortname = "record-core"; - record_core_ops.to_longname = "Process record and replay target"; - record_core_ops.to_doc = - "Log program while executing and replay execution from log."; - record_core_ops.to_open = record_open; - record_core_ops.to_close = record_close; - record_core_ops.to_resume = record_core_resume; - record_core_ops.to_wait = record_wait; - record_core_ops.to_kill = record_core_kill; - record_core_ops.to_fetch_registers = record_core_fetch_registers; - record_core_ops.to_prepare_to_store = record_core_prepare_to_store; - record_core_ops.to_store_registers = record_core_store_registers; - record_core_ops.to_xfer_partial = record_core_xfer_partial; - record_core_ops.to_insert_breakpoint = record_core_insert_breakpoint; - record_core_ops.to_remove_breakpoint = record_core_remove_breakpoint; - record_core_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint; - record_core_ops.to_stopped_data_address = record_stopped_data_address; - record_core_ops.to_can_execute_reverse = record_can_execute_reverse; - record_core_ops.to_has_execution = record_core_has_execution; - record_core_ops.to_stratum = record_stratum; - /* Add bookmark target methods. */ - record_core_ops.to_get_bookmark = record_get_bookmark; - record_core_ops.to_goto_bookmark = record_goto_bookmark; - record_core_ops.to_async = record_async; - record_core_ops.to_can_async_p = record_can_async_p; - record_core_ops.to_is_async_p = record_is_async_p; - record_core_ops.to_execution_direction = record_execution_direction; - record_core_ops.to_magic = OPS_MAGIC; + DEBUG ("kill %s", t->to_shortname); + + /* It is safer to not stop recording. Resources will be freed when + threads are discarded. */ + record_unpush (t); + + target_kill (); } /* Implement "show record debug" command. */ @@ -2122,7 +190,7 @@ show_record_debug (struct ui_file *file, int from_tty, static void cmd_record_start (char *args, int from_tty) { - execute_command ("target record", from_tty); + execute_command ("target record-full", from_tty); } /* Truncate the record log from the present point @@ -2131,21 +199,25 @@ cmd_record_start (char *args, int from_tty) static void cmd_record_delete (char *args, int from_tty) { - if (current_target.to_stratum == record_stratum) + require_record_target (); + + if (!target_record_is_replaying ()) { - if (RECORD_IS_REPLAY) - { - if (!from_tty || query (_("Delete the log from this point forward " - "and begin to record the running message " - "at current PC?"))) - record_list_release_following (record_list); - } - else - printf_unfiltered (_("Already at end of record list.\n")); + printf_unfiltered (_("Already at end of record list.\n")); + return; + } + if (!target_supports_delete_record ()) + { + printf_unfiltered (_("The current record target does not support " + "this operation.\n")); + return; } - else - printf_unfiltered (_("Process record is not started.\n")); + + if (!from_tty || query (_("Delete the log from this point forward " + "and begin to record the running message " + "at current PC?"))) + target_delete_record (); } /* Implement the "stoprecord" or "record stop" command. */ @@ -2153,34 +225,20 @@ cmd_record_delete (char *args, int from_tty) static void cmd_record_stop (char *args, int from_tty) { - if (current_target.to_stratum == record_stratum) - { - unpush_target (&record_ops); - printf_unfiltered (_("Process record is stopped and all execution " - "logs are deleted.\n")); - } - else - printf_unfiltered (_("Process record is not started.\n")); -} + struct target_ops *t; -/* Set upper limit of record log size. */ + t = require_record_target (); -static void -set_record_insn_max_num (char *args, int from_tty, struct cmd_list_element *c) -{ - if (record_insn_num > record_insn_max_num && record_insn_max_num) - { - /* Count down record_insn_num while releasing records from list. */ - while (record_insn_num > record_insn_max_num) - { - record_list_release_first (); - record_insn_num--; - } - } + record_stop (t); + record_unpush (t); + + printf_unfiltered (_("Process record is stopped and all execution " + "logs are deleted.\n")); + + observer_notify_record_changed (current_inferior (), 0); } -static struct cmd_list_element *record_cmdlist, *set_record_cmdlist, - *show_record_cmdlist, *info_record_cmdlist; +/* The "set record" command. */ static void set_record_command (char *args, int from_tty) @@ -2190,703 +248,407 @@ set_record_command (char *args, int from_tty) help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout); } +/* The "show record" command. */ + static void show_record_command (char *args, int from_tty) { cmd_show_list (show_record_cmdlist, from_tty, ""); } -/* Display some statistics about the execution log. */ +/* The "info record" command. */ static void info_record_command (char *args, int from_tty) { - struct record_entry *p; + struct target_ops *t; - if (current_target.to_stratum == record_stratum) + t = find_record_target (); + if (t == NULL) { - if (RECORD_IS_REPLAY) - printf_filtered (_("Replay mode:\n")); - else - printf_filtered (_("Record mode:\n")); + printf_filtered (_("No record target is currently active.\n")); + return; + } - /* Find entry for first actual instruction in the log. */ - for (p = record_first.next; - p != NULL && p->type != record_end; - p = p->next) - ; + printf_filtered (_("Active record target: %s\n"), t->to_shortname); + if (t->to_info_record != NULL) + t->to_info_record (); +} - /* Do we have a log at all? */ - if (p != NULL && p->type == record_end) - { - /* Display instruction number for first instruction in the log. */ - printf_filtered (_("Lowest recorded instruction number is %s.\n"), - pulongest (p->u.end.insn_num)); - - /* If in replay mode, display where we are in the log. */ - if (RECORD_IS_REPLAY) - printf_filtered (_("Current instruction number is %s.\n"), - pulongest (record_list->u.end.insn_num)); - - /* Display instruction number for last instruction in the log. */ - printf_filtered (_("Highest recorded instruction number is %s.\n"), - pulongest (record_insn_count)); - - /* Display log count. */ - printf_filtered (_("Log contains %d instructions.\n"), - record_insn_num); - } - else - { - printf_filtered (_("No instructions have been logged.\n")); - } - } +/* The "record save" command. */ + +static void +cmd_record_save (char *args, int from_tty) +{ + char *recfilename, recfilename_buffer[40]; + + require_record_target (); + + if (args != NULL && *args != 0) + recfilename = args; else { - printf_filtered (_("target record is not active.\n")); + /* Default recfile name is "gdb_record.PID". */ + xsnprintf (recfilename_buffer, sizeof (recfilename_buffer), + "gdb_record.%d", PIDGET (inferior_ptid)); + recfilename = recfilename_buffer; } - /* Display max log size. */ - printf_filtered (_("Max logged instructions is %d.\n"), - record_insn_max_num); + target_save_record (recfilename); } -/* Record log save-file format - Version 1 (never released) - - Header: - 4 bytes: magic number htonl(0x20090829). - NOTE: be sure to change whenever this file format changes! - - Records: - record_end: - 1 byte: record type (record_end, see enum record_type). - record_reg: - 1 byte: record type (record_reg, see enum record_type). - 8 bytes: register id (network byte order). - MAX_REGISTER_SIZE bytes: register value. - record_mem: - 1 byte: record type (record_mem, see enum record_type). - 8 bytes: memory length (network byte order). - 8 bytes: memory address (network byte order). - n bytes: memory value (n == memory length). - - Version 2 - 4 bytes: magic number netorder32(0x20091016). - NOTE: be sure to change whenever this file format changes! - - Records: - record_end: - 1 byte: record type (record_end, see enum record_type). - 4 bytes: signal - 4 bytes: instruction count - record_reg: - 1 byte: record type (record_reg, see enum record_type). - 4 bytes: register id (network byte order). - n bytes: register value (n == actual register size). - (eg. 4 bytes for x86 general registers). - record_mem: - 1 byte: record type (record_mem, see enum record_type). - 4 bytes: memory length (network byte order). - 8 bytes: memory address (network byte order). - n bytes: memory value (n == memory length). - -*/ - -/* bfdcore_read -- read bytes from a core file section. */ - -static inline void -bfdcore_read (bfd *obfd, asection *osec, void *buf, int len, int *offset) +/* "record goto" command. Argument is an instruction number, + as given by "info record". + + Rewinds the recording (forward or backward) to the given instruction. */ + +void +cmd_record_goto (char *arg, int from_tty) { - int ret = bfd_get_section_contents (obfd, osec, buf, *offset, len); + require_record_target (); - if (ret) - *offset += len; + if (arg == NULL || *arg == '\0') + error (_("Command requires an argument (insn number to go to).")); + + if (strncmp (arg, "start", strlen ("start")) == 0 + || strncmp (arg, "begin", strlen ("begin")) == 0) + target_goto_record_begin (); + else if (strncmp (arg, "end", strlen ("end")) == 0) + target_goto_record_end (); else - error (_("Failed to read %d bytes from core file %s ('%s')."), - len, bfd_get_filename (obfd), - bfd_errmsg (bfd_get_error ())); + { + ULONGEST insn; + + insn = parse_and_eval_long (arg); + target_goto_record (insn); + } } -static inline uint64_t -netorder64 (uint64_t input) +/* Read an instruction number from an argument string. */ + +static ULONGEST +get_insn_number (char **arg) { - uint64_t ret; + ULONGEST number; + const char *begin, *end, *pos; - store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret), - BFD_ENDIAN_BIG, input); - return ret; -} + begin = *arg; + pos = skip_spaces_const (begin); -static inline uint32_t -netorder32 (uint32_t input) -{ - uint32_t ret; + if (!isdigit (*pos)) + error (_("Expected positive number, got: %s."), pos); - store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret), - BFD_ENDIAN_BIG, input); - return ret; + number = strtoulst (pos, &end, 10); + + *arg += (end - begin); + + return number; } -static inline uint16_t -netorder16 (uint16_t input) +/* Read a context size from an argument string. */ + +static int +get_context_size (char **arg) { - uint16_t ret; + char *pos; + int number; - store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret), - BFD_ENDIAN_BIG, input); - return ret; + pos = skip_spaces (*arg); + + if (!isdigit (*pos)) + error (_("Expected positive number, got: %s."), pos); + + return strtol (pos, arg, 10); } -/* Restore the execution log from a core_bfd file. */ +/* Complain about junk at the end of an argument string. */ + static void -record_restore (void) +no_chunk (char *arg) { - uint32_t magic; - struct cleanup *old_cleanups; - struct record_entry *rec; - asection *osec; - uint32_t osec_size; - int bfd_offset = 0; - struct regcache *regcache; - - /* We restore the execution log from the open core bfd, - if there is one. */ - if (core_bfd == NULL) - return; - - /* "record_restore" can only be called when record list is empty. */ - gdb_assert (record_first.next == NULL); - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Restoring recording from core file.\n"); - - /* Now need to find our special note section. */ - osec = bfd_get_section_by_name (core_bfd, "null0"); - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Find precord section %s.\n", - osec ? "succeeded" : "failed"); - if (osec == NULL) - return; - osec_size = bfd_section_size (core_bfd, osec); - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (core_bfd, osec)); - - /* Check the magic code. */ - bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset); - if (magic != RECORD_FILE_MAGIC) - error (_("Version mis-match or file format error in core file %s."), - bfd_get_filename (core_bfd)); - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - " Reading 4-byte magic cookie " - "RECORD_FILE_MAGIC (0x%s)\n", - phex_nz (netorder32 (magic), 4)); - - /* Restore the entries in recfd into record_arch_list_head and - record_arch_list_tail. */ - record_arch_list_head = NULL; - record_arch_list_tail = NULL; - record_insn_num = 0; - old_cleanups = make_cleanup (record_arch_list_cleanups, 0); - regcache = get_current_regcache (); - - while (1) - { - uint8_t rectype; - uint32_t regnum, len, signal, count; - uint64_t addr; - - /* We are finished when offset reaches osec_size. */ - if (bfd_offset >= osec_size) - break; - bfdcore_read (core_bfd, osec, &rectype, sizeof (rectype), &bfd_offset); - - switch (rectype) - { - case record_reg: /* reg */ - /* Get register number to regnum. */ - bfdcore_read (core_bfd, osec, ®num, - sizeof (regnum), &bfd_offset); - regnum = netorder32 (regnum); - - rec = record_reg_alloc (regcache, regnum); - - /* Get val. */ - bfdcore_read (core_bfd, osec, record_get_loc (rec), - rec->u.reg.len, &bfd_offset); - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - " Reading register %d (1 " - "plus %lu plus %d bytes)\n", - rec->u.reg.num, - (unsigned long) sizeof (regnum), - rec->u.reg.len); - break; - - case record_mem: /* mem */ - /* Get len. */ - bfdcore_read (core_bfd, osec, &len, - sizeof (len), &bfd_offset); - len = netorder32 (len); - - /* Get addr. */ - bfdcore_read (core_bfd, osec, &addr, - sizeof (addr), &bfd_offset); - addr = netorder64 (addr); - - rec = record_mem_alloc (addr, len); - - /* Get val. */ - bfdcore_read (core_bfd, osec, record_get_loc (rec), - rec->u.mem.len, &bfd_offset); - - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - " Reading memory %s (1 plus " - "%lu plus %lu plus %d bytes)\n", - paddress (get_current_arch (), - rec->u.mem.addr), - (unsigned long) sizeof (addr), - (unsigned long) sizeof (len), - rec->u.mem.len); - break; - - case record_end: /* end */ - rec = record_end_alloc (); - record_insn_num ++; - - /* Get signal value. */ - bfdcore_read (core_bfd, osec, &signal, - sizeof (signal), &bfd_offset); - signal = netorder32 (signal); - rec->u.end.sigval = signal; - - /* Get insn count. */ - bfdcore_read (core_bfd, osec, &count, - sizeof (count), &bfd_offset); - count = netorder32 (count); - rec->u.end.insn_num = count; - record_insn_count = count + 1; - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - " Reading record_end (1 + " - "%lu + %lu bytes), offset == %s\n", - (unsigned long) sizeof (signal), - (unsigned long) sizeof (count), - paddress (get_current_arch (), - bfd_offset)); - break; - - default: - error (_("Bad entry type in core file %s."), - bfd_get_filename (core_bfd)); - break; - } - - /* Add rec to record arch list. */ - record_arch_list_add (rec); - } + if (*arg != 0) + error (_("Junk after argument: %s."), arg); +} + +/* Read instruction-history modifiers from an argument string. */ + +static int +get_insn_history_modifiers (char **arg) +{ + int modifiers; + char *args; - discard_cleanups (old_cleanups); + modifiers = 0; + args = *arg; - /* Add record_arch_list_head to the end of record list. */ - record_first.next = record_arch_list_head; - record_arch_list_head->prev = &record_first; - record_arch_list_tail->next = NULL; - record_list = &record_first; + if (args == NULL) + return modifiers; - /* Update record_insn_max_num. */ - if (record_insn_num > record_insn_max_num) + while (*args == '/') { - record_insn_max_num = record_insn_num; - warning (_("Auto increase record/replay buffer limit to %d."), - record_insn_max_num); - } + ++args; - /* Succeeded. */ - printf_filtered (_("Restored records from core file %s.\n"), - bfd_get_filename (core_bfd)); + if (*args == '\0') + error (_("Missing modifier.")); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); -} + for (; *args; ++args) + { + if (isspace (*args)) + break; -/* bfdcore_write -- write bytes into a core file section. */ + if (*args == '/') + continue; -static inline void -bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset) -{ - int ret = bfd_set_section_contents (obfd, osec, buf, *offset, len); + switch (*args) + { + case 'm': + modifiers |= DISASSEMBLY_SOURCE; + modifiers |= DISASSEMBLY_FILENAME; + break; + case 'r': + modifiers |= DISASSEMBLY_RAW_INSN; + break; + case 'f': + modifiers |= DISASSEMBLY_OMIT_FNAME; + break; + case 'p': + modifiers |= DISASSEMBLY_OMIT_PC; + break; + default: + error (_("Invalid modifier: %c."), *args); + } + } - if (ret) - *offset += len; - else - error (_("Failed to write %d bytes to core file %s ('%s')."), - len, bfd_get_filename (obfd), - bfd_errmsg (bfd_get_error ())); -} + args = skip_spaces (args); + } -/* Restore the execution log from a file. We use a modified elf - corefile format, with an extra section for our data. */ + /* Update the argument string. */ + *arg = args; -static void -cmd_record_restore (char *args, int from_tty) -{ - core_file_command (args, from_tty); - record_open (args, from_tty); + return modifiers; } +/* The "record instruction-history" command. */ + static void -record_save_cleanups (void *data) +cmd_record_insn_history (char *arg, int from_tty) { - bfd *obfd = data; - char *pathname = xstrdup (bfd_get_filename (obfd)); + int flags, size; - bfd_close (obfd); - unlink (pathname); - xfree (pathname); -} + require_record_target (); -/* Save the execution log to a file. We use a modified elf corefile - format, with an extra section for our data. */ + flags = get_insn_history_modifiers (&arg); -static void -cmd_record_save (char *args, int from_tty) -{ - char *recfilename, recfilename_buffer[40]; - struct record_entry *cur_record_list; - uint32_t magic; - struct regcache *regcache; - struct gdbarch *gdbarch; - struct cleanup *old_cleanups; - struct cleanup *set_cleanups; - bfd *obfd; - int save_size = 0; - asection *osec = NULL; - int bfd_offset = 0; - - if (strcmp (current_target.to_shortname, "record") != 0) - error (_("This command can only be used with target 'record'.\n" - "Use 'target record' first.\n")); - - if (args && *args) - recfilename = args; + /* We use a signed size to also indicate the direction. Make sure that + unlimited remains unlimited. */ + size = (int) record_insn_history_size; + if (size < 0) + size = INT_MAX; + + if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) + target_insn_history (size, flags); + else if (strcmp (arg, "-") == 0) + target_insn_history (-size, flags); else { - /* Default recfile name is "gdb_record.PID". */ - snprintf (recfilename_buffer, sizeof (recfilename_buffer), - "gdb_record.%d", PIDGET (inferior_ptid)); - recfilename = recfilename_buffer; - } + ULONGEST begin, end; - /* Open the save file. */ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, "Saving execution log to core file '%s'\n", - recfilename); + begin = get_insn_number (&arg); - /* Open the output file. */ - obfd = create_gcore_bfd (recfilename); - old_cleanups = make_cleanup (record_save_cleanups, obfd); + if (*arg == ',') + { + arg = skip_spaces (++arg); - /* Save the current record entry to "cur_record_list". */ - cur_record_list = record_list; + if (*arg == '+') + { + arg += 1; + size = get_context_size (&arg); - /* Get the values of regcache and gdbarch. */ - regcache = get_current_regcache (); - gdbarch = get_regcache_arch (regcache); + no_chunk (arg); - /* Disable the GDB operation record. */ - set_cleanups = record_gdb_operation_disable_set (); + target_insn_history_from (begin, size, flags); + } + else if (*arg == '-') + { + arg += 1; + size = get_context_size (&arg); - /* Reverse execute to the begin of record list. */ - while (1) - { - /* Check for beginning and end of log. */ - if (record_list == &record_first) - break; + no_chunk (arg); - record_exec_insn (regcache, gdbarch, record_list); + target_insn_history_from (begin, -size, flags); + } + else + { + end = get_insn_number (&arg); - if (record_list->prev) - record_list = record_list->prev; - } + no_chunk (arg); - /* Compute the size needed for the extra bfd section. */ - save_size = 4; /* magic cookie */ - for (record_list = record_first.next; record_list; - record_list = record_list->next) - switch (record_list->type) - { - case record_end: - save_size += 1 + 4 + 4; - break; - case record_reg: - save_size += 1 + 4 + record_list->u.reg.len; - break; - case record_mem: - save_size += 1 + 4 + 8 + record_list->u.mem.len; - break; - } - - /* Make the new bfd section. */ - osec = bfd_make_section_anyway_with_flags (obfd, "precord", - SEC_HAS_CONTENTS - | SEC_READONLY); - if (osec == NULL) - error (_("Failed to create 'precord' section for corefile %s: %s"), - recfilename, - bfd_errmsg (bfd_get_error ())); - bfd_set_section_size (obfd, osec, save_size); - bfd_set_section_vma (obfd, osec, 0); - bfd_set_section_alignment (obfd, osec, 0); - bfd_section_lma (obfd, osec) = 0; - - /* Save corefile state. */ - write_gcore_file (obfd); - - /* Write out the record log. */ - /* Write the magic code. */ - magic = RECORD_FILE_MAGIC; - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - " Writing 4-byte magic cookie " - "RECORD_FILE_MAGIC (0x%s)\n", - phex_nz (magic, 4)); - bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset); - - /* Save the entries to recfd and forward execute to the end of - record list. */ - record_list = &record_first; - while (1) - { - /* Save entry. */ - if (record_list != &record_first) - { - uint8_t type; - uint32_t regnum, len, signal, count; - uint64_t addr; - - type = record_list->type; - bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset); - - switch (record_list->type) - { - case record_reg: /* reg */ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - " Writing register %d (1 " - "plus %lu plus %d bytes)\n", - record_list->u.reg.num, - (unsigned long) sizeof (regnum), - record_list->u.reg.len); - - /* Write regnum. */ - regnum = netorder32 (record_list->u.reg.num); - bfdcore_write (obfd, osec, ®num, - sizeof (regnum), &bfd_offset); - - /* Write regval. */ - bfdcore_write (obfd, osec, record_get_loc (record_list), - record_list->u.reg.len, &bfd_offset); - break; - - case record_mem: /* mem */ - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - " Writing memory %s (1 plus " - "%lu plus %lu plus %d bytes)\n", - paddress (gdbarch, - record_list->u.mem.addr), - (unsigned long) sizeof (addr), - (unsigned long) sizeof (len), - record_list->u.mem.len); - - /* Write memlen. */ - len = netorder32 (record_list->u.mem.len); - bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset); - - /* Write memaddr. */ - addr = netorder64 (record_list->u.mem.addr); - bfdcore_write (obfd, osec, &addr, - sizeof (addr), &bfd_offset); - - /* Write memval. */ - bfdcore_write (obfd, osec, record_get_loc (record_list), - record_list->u.mem.len, &bfd_offset); - break; - - case record_end: - if (record_debug) - fprintf_unfiltered (gdb_stdlog, - " Writing record_end (1 + " - "%lu + %lu bytes)\n", - (unsigned long) sizeof (signal), - (unsigned long) sizeof (count)); - /* Write signal value. */ - signal = netorder32 (record_list->u.end.sigval); - bfdcore_write (obfd, osec, &signal, - sizeof (signal), &bfd_offset); - - /* Write insn count. */ - count = netorder32 (record_list->u.end.insn_num); - bfdcore_write (obfd, osec, &count, - sizeof (count), &bfd_offset); - break; - } - } - - /* Execute entry. */ - record_exec_insn (regcache, gdbarch, record_list); - - if (record_list->next) - record_list = record_list->next; + target_insn_history_range (begin, end, flags); + } + } else - break; + { + no_chunk (arg); + + target_insn_history_from (begin, size, flags); + } + + dont_repeat (); } +} + +/* Read function-call-history modifiers from an argument string. */ + +static int +get_call_history_modifiers (char **arg) +{ + int modifiers; + char *args; + + modifiers = 0; + args = *arg; + + if (args == NULL) + return modifiers; - /* Reverse execute to cur_record_list. */ - while (1) + while (*args == '/') { - /* Check for beginning and end of log. */ - if (record_list == cur_record_list) - break; + ++args; + + if (*args == '\0') + error (_("Missing modifier.")); + + for (; *args; ++args) + { + if (isspace (*args)) + break; + + if (*args == '/') + continue; - record_exec_insn (regcache, gdbarch, record_list); + switch (*args) + { + case 'l': + modifiers |= record_print_src_line; + break; + case 'i': + modifiers |= record_print_insn_range; + break; + default: + error (_("Invalid modifier: %c."), *args); + } + } - if (record_list->prev) - record_list = record_list->prev; + args = skip_spaces (args); } - do_cleanups (set_cleanups); - bfd_close (obfd); - discard_cleanups (old_cleanups); + /* Update the argument string. */ + *arg = args; - /* Succeeded. */ - printf_filtered (_("Saved core file %s with execution log.\n"), - recfilename); + return modifiers; } -/* record_goto_insn -- rewind the record log (forward or backward, - depending on DIR) to the given entry, changing the program state - correspondingly. */ +/* The "record function-call-history" command. */ static void -record_goto_insn (struct record_entry *entry, - enum exec_direction_kind dir) +cmd_record_call_history (char *arg, int from_tty) { - struct cleanup *set_cleanups = record_gdb_operation_disable_set (); - struct regcache *regcache = get_current_regcache (); - struct gdbarch *gdbarch = get_regcache_arch (regcache); + int flags, size; + + require_record_target (); - /* Assume everything is valid: we will hit the entry, - and we will not hit the end of the recording. */ + flags = get_call_history_modifiers (&arg); - if (dir == EXEC_FORWARD) - record_list = record_list->next; + /* We use a signed size to also indicate the direction. Make sure that + unlimited remains unlimited. */ + size = (int) record_call_history_size; + if (size < 0) + size = INT_MAX; - do + if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) + target_call_history (size, flags); + else if (strcmp (arg, "-") == 0) + target_call_history (-size, flags); + else { - record_exec_insn (regcache, gdbarch, record_list); - if (dir == EXEC_REVERSE) - record_list = record_list->prev; - else - record_list = record_list->next; - } while (record_list != entry); - do_cleanups (set_cleanups); -} + ULONGEST begin, end; -/* "record goto" command. Argument is an instruction number, - as given by "info record". + begin = get_insn_number (&arg); - Rewinds the recording (forward or backward) to the given instruction. */ + if (*arg == ',') + { + arg = skip_spaces (++arg); -static void -cmd_record_goto (char *arg, int from_tty) -{ - struct record_entry *p = NULL; - ULONGEST target_insn = 0; + if (*arg == '+') + { + arg += 1; + size = get_context_size (&arg); - if (arg == NULL || *arg == '\0') - error (_("Command requires an argument (insn number to go to).")); + no_chunk (arg); - if (strncmp (arg, "start", strlen ("start")) == 0 - || strncmp (arg, "begin", strlen ("begin")) == 0) - { - /* Special case. Find first insn. */ - for (p = &record_first; p != NULL; p = p->next) - if (p->type == record_end) - break; - if (p) - target_insn = p->u.end.insn_num; - } - else if (strncmp (arg, "end", strlen ("end")) == 0) - { - /* Special case. Find last insn. */ - for (p = record_list; p->next != NULL; p = p->next) - ; - for (; p!= NULL; p = p->prev) - if (p->type == record_end) - break; - if (p) - target_insn = p->u.end.insn_num; - } - else - { - /* General case. Find designated insn. */ - target_insn = parse_and_eval_long (arg); + target_call_history_from (begin, size, flags); + } + else if (*arg == '-') + { + arg += 1; + size = get_context_size (&arg); - for (p = &record_first; p != NULL; p = p->next) - if (p->type == record_end && p->u.end.insn_num == target_insn) - break; - } + no_chunk (arg); - if (p == NULL) - error (_("Target insn '%s' not found."), arg); - else if (p == record_list) - error (_("Already at insn '%s'."), arg); - else if (p->u.end.insn_num > record_list->u.end.insn_num) - { - printf_filtered (_("Go forward to insn number %s\n"), - pulongest (target_insn)); - record_goto_insn (p, EXEC_FORWARD); - } - else - { - printf_filtered (_("Go backward to insn number %s\n"), - pulongest (target_insn)); - record_goto_insn (p, EXEC_REVERSE); + target_call_history_from (begin, -size, flags); + } + else + { + end = get_insn_number (&arg); + + no_chunk (arg); + + target_call_history_range (begin, end, flags); + } + } + else + { + no_chunk (arg); + + target_call_history_from (begin, size, flags); + } + + dont_repeat (); } - registers_changed (); - reinit_frame_cache (); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); } +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_record; + void _initialize_record (void) { struct cmd_list_element *c; - /* Init record_first. */ - record_first.prev = NULL; - record_first.next = NULL; - record_first.type = record_end; - - init_record_ops (); - add_target (&record_ops); - init_record_core_ops (); - add_target (&record_core_ops); - - add_setshow_zinteger_cmd ("record", no_class, &record_debug, - _("Set debugging of record/replay feature."), - _("Show debugging of record/replay feature."), - _("When enabled, debugging output for " - "record/replay feature is displayed."), - NULL, show_record_debug, &setdebuglist, - &showdebuglist); + add_setshow_zuinteger_cmd ("record", no_class, &record_debug, + _("Set debugging of record/replay feature."), + _("Show debugging of record/replay feature."), + _("When enabled, debugging output for " + "record/replay feature is displayed."), + NULL, show_record_debug, &setdebuglist, + &showdebuglist); + + add_setshow_uinteger_cmd ("instruction-history-size", no_class, + &record_insn_history_size, _("\ +Set number of instructions to print in \"record instruction-history\"."), _("\ +Show number of instructions to print in \"record instruction-history\"."), + NULL, NULL, NULL, &set_record_cmdlist, + &show_record_cmdlist); + + add_setshow_uinteger_cmd ("function-call-history-size", no_class, + &record_call_history_size, _("\ +Set number of function to print in \"record function-call-history\"."), _("\ +Show number of functions to print in \"record function-call-history\"."), + NULL, NULL, NULL, &set_record_cmdlist, + &show_record_cmdlist); c = add_prefix_cmd ("record", class_obscure, cmd_record_start, - _("Abbreviated form of \"target record\" command."), + _("Start recording."), &record_cmdlist, "record ", 0, &cmdlist); set_cmd_completer (c, filename_completer); @@ -2911,12 +673,6 @@ Default filename is 'gdb_record.'."), &record_cmdlist); set_cmd_completer (c, filename_completer); - c = add_cmd ("restore", class_obscure, cmd_record_restore, - _("Restore the execution log from a file.\n\ -Argument is filename. File must be created with 'record save'."), - &record_cmdlist); - set_cmd_completer (c, filename_completer); - add_cmd ("delete", class_obscure, cmd_record_delete, _("Delete the rest of execution log and start recording it anew."), &record_cmdlist); @@ -2928,40 +684,47 @@ Argument is filename. File must be created with 'record save'."), &record_cmdlist); add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist); - /* Record instructions number limit command. */ - add_setshow_boolean_cmd ("stop-at-limit", no_class, - &record_stop_at_limit, _("\ -Set whether record/replay stops when record/replay buffer becomes full."), _("\ -Show whether record/replay stops when record/replay buffer becomes full."), - _("Default is ON.\n\ -When ON, if the record/replay buffer becomes full, ask user what to do.\n\ -When OFF, if the record/replay buffer becomes full,\n\ -delete the oldest recorded instruction to make room for each new one."), - NULL, NULL, - &set_record_cmdlist, &show_record_cmdlist); - add_setshow_uinteger_cmd ("insn-number-max", no_class, - &record_insn_max_num, - _("Set record/replay buffer limit."), - _("Show record/replay buffer limit."), _("\ -Set the maximum number of instructions to be stored in the\n\ -record/replay buffer. Zero means unlimited. Default is 200000."), - set_record_insn_max_num, - NULL, &set_record_cmdlist, &show_record_cmdlist); - add_cmd ("goto", class_obscure, cmd_record_goto, _("\ Restore the program to its state at instruction number N.\n\ Argument is instruction number, as shown by 'info record'."), &record_cmdlist); - add_setshow_boolean_cmd ("memory-query", no_class, - &record_memory_query, _("\ -Set whether query if PREC cannot record memory change of next instruction."), - _("\ -Show whether query if PREC cannot record memory change of next instruction."), - _("\ -Default is OFF.\n\ -When ON, query if PREC cannot record memory change of next instruction."), - NULL, NULL, - &set_record_cmdlist, &show_record_cmdlist); + add_cmd ("instruction-history", class_obscure, cmd_record_insn_history, _("\ +Print disassembled instructions stored in the execution log.\n\ +With a /m modifier, source lines are included (if available).\n\ +With a /r modifier, raw instructions in hex are included.\n\ +With a /f modifier, function names are omitted.\n\ +With a /p modifier, current position markers are omitted.\n\ +With no argument, disassembles ten more instructions after the previous \ +disassembly.\n\ +\"record instruction-history -\" disassembles ten instructions before a \ +previous disassembly.\n\ +One argument specifies an instruction number as shown by 'info record', and \ +ten instructions are disassembled after that instruction.\n\ +Two arguments with comma between them specify starting and ending instruction \ +numbers to disassemble.\n\ +If the second argument is preceded by '+' or '-', it specifies the distance \ +from the first argument.\n\ +The number of instructions to disassemble can be defined with \"set record \ +instruction-history-size\"."), + &record_cmdlist); + add_cmd ("function-call-history", class_obscure, cmd_record_call_history, _("\ +Prints the execution history at function granularity.\n\ +It prints one line for each sequence of instructions that belong to the same \ +function.\n\ +Without modifiers, it prints the function name.\n\ +With a /l modifier, the source file and line number range is included.\n\ +With a /i modifier, the instruction number range is included.\n\ +With no argument, prints ten more lines after the previous ten-line print.\n\ +\"record function-call-history -\" prints ten lines before a previous ten-line \ +print.\n\ +One argument specifies a function number as shown by 'info record', and \ +ten lines are printed after that function.\n\ +Two arguments with comma between them specify a range of functions to print.\n\ +If the second argument is preceded by '+' or '-', it specifies the distance \ +from the first argument.\n\ +The number of functions to print can be defined with \"set record \ +function-call-history-size\"."), + &record_cmdlist); } diff --git a/contrib/gdb-7/gdb/record.h b/contrib/gdb-7/gdb/record.h index 84396e66cb..86e6bc691d 100644 --- a/contrib/gdb-7/gdb/record.h +++ b/contrib/gdb-7/gdb/record.h @@ -1,6 +1,6 @@ /* Process record and replay target for GDB, the GNU debugger. - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -20,14 +20,47 @@ #ifndef _RECORD_H_ #define _RECORD_H_ +struct cmd_list_element; + #define RECORD_IS_USED (current_target.to_stratum == record_stratum) -extern int record_debug; -extern int record_memory_query; +extern unsigned int record_debug; + +/* Allow record targets to add their own sub-commands. */ +extern struct cmd_list_element *record_cmdlist; +extern struct cmd_list_element *set_record_cmdlist; +extern struct cmd_list_element *show_record_cmdlist; +extern struct cmd_list_element *info_record_cmdlist; + +/* A list of flags specifying what record target methods should print. */ +enum record_print_flag +{ + /* Print the source file and line (if applicable). */ + record_print_src_line = (1 << 0), + + /* Print the instruction number range (if applicable). */ + record_print_insn_range = (1 << 1), +}; + +/* Wrapper for target_read_memory that prints a debug message if + reading memory fails. */ +extern int record_read_memory (struct gdbarch *gdbarch, + CORE_ADDR memaddr, gdb_byte *myaddr, + ssize_t len); + +/* The "record goto" command. */ +extern void cmd_record_goto (char *arg, int from_tty); + +/* The default "to_disconnect" target method for record targets. */ +extern void record_disconnect (struct target_ops *, char *, int); + +/* The default "to_detach" target method for record targets. */ +extern void record_detach (struct target_ops *, char *, int); + +/* The default "to_mourn_inferior" target method for record targets. */ +extern void record_mourn_inferior (struct target_ops *); -extern int record_arch_list_add_reg (struct regcache *regcache, int num); -extern int record_arch_list_add_mem (CORE_ADDR addr, int len); -extern int record_arch_list_add_end (void); -extern struct cleanup *record_gdb_operation_disable_set (void); +/* The default "to_kill" target method for record targets. */ +extern void record_kill (struct target_ops *); #endif /* _RECORD_H_ */ diff --git a/contrib/gdb-7/gdb/regcache.c b/contrib/gdb-7/gdb/regcache.c index c716280237..57d29e4b64 100644 --- a/contrib/gdb-7/gdb/regcache.c +++ b/contrib/gdb-7/gdb/regcache.c @@ -1,7 +1,6 @@ /* Cache and manage the values of registers for GDB, the GNU debugger. - Copyright (C) 1986-1987, 1989, 1991, 1994-1996, 1998, 2000-2002, - 2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -226,14 +225,14 @@ regcache_xmalloc_1 (struct gdbarch *gdbarch, struct address_space *aspace, regcache->registers = XCALLOC (descr->sizeof_cooked_registers, gdb_byte); regcache->register_status - = XCALLOC (descr->sizeof_cooked_register_status, gdb_byte); + = XCALLOC (descr->sizeof_cooked_register_status, signed char); } else { regcache->registers = XCALLOC (descr->sizeof_raw_registers, gdb_byte); regcache->register_status - = XCALLOC (descr->sizeof_raw_register_status, gdb_byte); + = XCALLOC (descr->sizeof_raw_register_status, signed char); } regcache->aspace = aspace; regcache->ptid = minus_one_ptid; @@ -411,7 +410,7 @@ regcache_dup (struct regcache *src) return newbuf; } -int +enum register_status regcache_register_status (const struct regcache *regcache, int regnum) { gdb_assert (regcache != NULL); @@ -707,8 +706,6 @@ regcache_cooked_read (struct regcache *regcache, int regnum, gdb_byte *buf) { /* Read-only register cache, perhaps the cooked value was cached? */ - struct gdbarch *gdbarch = regcache->descr->gdbarch; - if (regcache->register_status[regnum] == REG_VALID) memcpy (buf, register_buffer (regcache, regnum), regcache->descr->sizeof_register[regnum]); @@ -1095,7 +1092,7 @@ reg_flush_command (char *command, int from_tty) static void dump_endian_bytes (struct ui_file *file, enum bfd_endian endian, - const unsigned char *buf, long len) + const gdb_byte *buf, long len) { int i; @@ -1133,7 +1130,7 @@ regcache_dump (struct regcache *regcache, struct ui_file *file, int footnote_register_offset = 0; int footnote_register_type_name_null = 0; long register_offset = 0; - unsigned char buf[MAX_REGISTER_SIZE]; + gdb_byte buf[MAX_REGISTER_SIZE]; #if 0 fprintf_unfiltered (file, "nr_raw_registers %d\n", diff --git a/contrib/gdb-7/gdb/regcache.h b/contrib/gdb-7/gdb/regcache.h index 93b449998e..bd9bb1c368 100644 --- a/contrib/gdb-7/gdb/regcache.h +++ b/contrib/gdb-7/gdb/regcache.h @@ -1,7 +1,6 @@ /* Cache and manage the values of registers for GDB, the GNU debugger. - Copyright (C) 1986-1987, 1989, 1991, 1994-1996, 1998, 2000-2002, - 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/regformats/i386/x32-avx-linux.dat b/contrib/gdb-7/gdb/regformats/i386/x32-avx-linux.dat new file mode 100644 index 0000000000..12038067f8 --- /dev/null +++ b/contrib/gdb-7/gdb/regformats/i386/x32-avx-linux.dat @@ -0,0 +1,78 @@ +# DO NOT EDIT: generated from i386/x32-avx-linux.xml +name:x32_avx_linux +xmltarget:x32-avx-linux.xml +expedite:rbp,rsp,rip +64:rax +64:rbx +64:rcx +64:rdx +64:rsi +64:rdi +64:rbp +64:rsp +64:r8 +64:r9 +64:r10 +64:r11 +64:r12 +64:r13 +64:r14 +64:r15 +64:rip +32:eflags +32:cs +32:ss +32:ds +32:es +32:fs +32:gs +80:st0 +80:st1 +80:st2 +80:st3 +80:st4 +80:st5 +80:st6 +80:st7 +32:fctrl +32:fstat +32:ftag +32:fiseg +32:fioff +32:foseg +32:fooff +32:fop +128:xmm0 +128:xmm1 +128:xmm2 +128:xmm3 +128:xmm4 +128:xmm5 +128:xmm6 +128:xmm7 +128:xmm8 +128:xmm9 +128:xmm10 +128:xmm11 +128:xmm12 +128:xmm13 +128:xmm14 +128:xmm15 +32:mxcsr +64:orig_rax +128:ymm0h +128:ymm1h +128:ymm2h +128:ymm3h +128:ymm4h +128:ymm5h +128:ymm6h +128:ymm7h +128:ymm8h +128:ymm9h +128:ymm10h +128:ymm11h +128:ymm12h +128:ymm13h +128:ymm14h +128:ymm15h diff --git a/contrib/gdb-7/gdb/regformats/i386/x32-avx.dat b/contrib/gdb-7/gdb/regformats/i386/x32-avx.dat new file mode 100644 index 0000000000..f13bf28040 --- /dev/null +++ b/contrib/gdb-7/gdb/regformats/i386/x32-avx.dat @@ -0,0 +1,77 @@ +# DO NOT EDIT: generated from i386/x32-avx.xml +name:x32_avx +xmltarget:x32-avx.xml +expedite:rbp,rsp,rip +64:rax +64:rbx +64:rcx +64:rdx +64:rsi +64:rdi +64:rbp +64:rsp +64:r8 +64:r9 +64:r10 +64:r11 +64:r12 +64:r13 +64:r14 +64:r15 +64:rip +32:eflags +32:cs +32:ss +32:ds +32:es +32:fs +32:gs +80:st0 +80:st1 +80:st2 +80:st3 +80:st4 +80:st5 +80:st6 +80:st7 +32:fctrl +32:fstat +32:ftag +32:fiseg +32:fioff +32:foseg +32:fooff +32:fop +128:xmm0 +128:xmm1 +128:xmm2 +128:xmm3 +128:xmm4 +128:xmm5 +128:xmm6 +128:xmm7 +128:xmm8 +128:xmm9 +128:xmm10 +128:xmm11 +128:xmm12 +128:xmm13 +128:xmm14 +128:xmm15 +32:mxcsr +128:ymm0h +128:ymm1h +128:ymm2h +128:ymm3h +128:ymm4h +128:ymm5h +128:ymm6h +128:ymm7h +128:ymm8h +128:ymm9h +128:ymm10h +128:ymm11h +128:ymm12h +128:ymm13h +128:ymm14h +128:ymm15h diff --git a/contrib/gdb-7/gdb/regformats/i386/x32-linux.dat b/contrib/gdb-7/gdb/regformats/i386/x32-linux.dat new file mode 100644 index 0000000000..6eda64afb8 --- /dev/null +++ b/contrib/gdb-7/gdb/regformats/i386/x32-linux.dat @@ -0,0 +1,62 @@ +# DO NOT EDIT: generated from i386/x32-linux.xml +name:x32_linux +xmltarget:x32-linux.xml +expedite:rbp,rsp,rip +64:rax +64:rbx +64:rcx +64:rdx +64:rsi +64:rdi +64:rbp +64:rsp +64:r8 +64:r9 +64:r10 +64:r11 +64:r12 +64:r13 +64:r14 +64:r15 +64:rip +32:eflags +32:cs +32:ss +32:ds +32:es +32:fs +32:gs +80:st0 +80:st1 +80:st2 +80:st3 +80:st4 +80:st5 +80:st6 +80:st7 +32:fctrl +32:fstat +32:ftag +32:fiseg +32:fioff +32:foseg +32:fooff +32:fop +128:xmm0 +128:xmm1 +128:xmm2 +128:xmm3 +128:xmm4 +128:xmm5 +128:xmm6 +128:xmm7 +128:xmm8 +128:xmm9 +128:xmm10 +128:xmm11 +128:xmm12 +128:xmm13 +128:xmm14 +128:xmm15 +32:mxcsr +64:orig_rax diff --git a/contrib/gdb-7/gdb/regformats/i386/x32.dat b/contrib/gdb-7/gdb/regformats/i386/x32.dat new file mode 100644 index 0000000000..6c63a8a40b --- /dev/null +++ b/contrib/gdb-7/gdb/regformats/i386/x32.dat @@ -0,0 +1,61 @@ +# DO NOT EDIT: generated from i386/x32.xml +name:x32 +xmltarget:x32.xml +expedite:rbp,rsp,rip +64:rax +64:rbx +64:rcx +64:rdx +64:rsi +64:rdi +64:rbp +64:rsp +64:r8 +64:r9 +64:r10 +64:r11 +64:r12 +64:r13 +64:r14 +64:r15 +64:rip +32:eflags +32:cs +32:ss +32:ds +32:es +32:fs +32:gs +80:st0 +80:st1 +80:st2 +80:st3 +80:st4 +80:st5 +80:st6 +80:st7 +32:fctrl +32:fstat +32:ftag +32:fiseg +32:fioff +32:foseg +32:fooff +32:fop +128:xmm0 +128:xmm1 +128:xmm2 +128:xmm3 +128:xmm4 +128:xmm5 +128:xmm6 +128:xmm7 +128:xmm8 +128:xmm9 +128:xmm10 +128:xmm11 +128:xmm12 +128:xmm13 +128:xmm14 +128:xmm15 +32:mxcsr diff --git a/contrib/gdb-7/gdb/regformats/regdat.sh b/contrib/gdb-7/gdb/regformats/regdat.sh index 3ca57fa4be..be4e01e39b 100755 --- a/contrib/gdb-7/gdb/regformats/regdat.sh +++ b/contrib/gdb-7/gdb/regformats/regdat.sh @@ -1,7 +1,7 @@ #!/bin/sh -u # Register protocol definitions for GDB, the GNU debugger. -# Copyright 2001-2002, 2007-2012 Free Software Foundation, Inc. +# Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is part of GDB. # @@ -94,7 +94,7 @@ cat <. */ + +#include "defs.h" +#include "registry.h" +#include "gdb_assert.h" +#include "gdb_string.h" + +const struct registry_data * +register_data_with_cleanup (struct registry_data_registry *registry, + registry_data_callback save, + registry_data_callback free) +{ + struct registry_data_registration **curr; + + /* Append new registration. */ + for (curr = ®istry->registrations; + *curr != NULL; + curr = &(*curr)->next) + ; + + *curr = XMALLOC (struct registry_data_registration); + (*curr)->next = NULL; + (*curr)->data = XMALLOC (struct registry_data); + (*curr)->data->index = registry->num_registrations++; + (*curr)->data->save = save; + (*curr)->data->free = free; + + return (*curr)->data; +} + +void +registry_alloc_data (struct registry_data_registry *registry, + struct registry_fields *fields) +{ + gdb_assert (fields->data == NULL); + fields->num_data = registry->num_registrations; + fields->data = XCALLOC (fields->num_data, void *); +} + +void +registry_clear_data (struct registry_data_registry *data_registry, + registry_callback_adaptor adaptor, + struct registry_container *container, + struct registry_fields *fields) +{ + struct registry_data_registration *registration; + int i; + + gdb_assert (fields->data != NULL); + + /* Process all the save handlers. */ + + for (registration = data_registry->registrations, i = 0; + i < fields->num_data; + registration = registration->next, i++) + if (fields->data[i] != NULL && registration->data->save != NULL) + adaptor (registration->data->save, container, fields->data[i]); + + /* Now process all the free handlers. */ + + for (registration = data_registry->registrations, i = 0; + i < fields->num_data; + registration = registration->next, i++) + if (fields->data[i] != NULL && registration->data->free != NULL) + adaptor (registration->data->free, container, fields->data[i]); + + memset (fields->data, 0, fields->num_data * sizeof (void *)); +} + +void +registry_container_free_data (struct registry_data_registry *data_registry, + registry_callback_adaptor adaptor, + struct registry_container *container, + struct registry_fields *fields) +{ + void ***rdata = &fields->data; + gdb_assert (*rdata != NULL); + registry_clear_data (data_registry, adaptor, container, fields); + xfree (*rdata); + *rdata = NULL; +} + +void +registry_set_data (struct registry_fields *fields, + const struct registry_data *data, + void *value) +{ + gdb_assert (data->index < fields->num_data); + fields->data[data->index] = value; +} + +void * +registry_data (struct registry_fields *fields, + const struct registry_data *data) +{ + gdb_assert (data->index < fields->num_data); + return fields->data[data->index]; +} diff --git a/contrib/gdb-7/gdb/registry.h b/contrib/gdb-7/gdb/registry.h new file mode 100644 index 0000000000..b3d1b55269 --- /dev/null +++ b/contrib/gdb-7/gdb/registry.h @@ -0,0 +1,256 @@ +/* Macros for general registry objects. + + Copyright (C) 2011-2013 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 REGISTRY_H +#define REGISTRY_H + +/* The macros here implement a template type and functions for + associating some user data with a container object. + + A registry is associated with a struct tag name. To attach a + registry to a structure, use DEFINE_REGISTRY. This takes the + structure tag and an access method as arguments. In the usual + case, where the registry fields appear directly in the struct, you + can use the 'REGISTRY_FIELDS' macro to declare the fields in the + struct definition, and you can pass 'REGISTRY_ACCESS_FIELD' as the + access argument to DEFINE_REGISTRY. In other cases, use + REGISTRY_FIELDS to define the fields in the appropriate spot, and + then define your own accessor to find the registry field structure + given an instance of your type. + + The API user requests a key from a registry during gdb + initialization. Later this key can be used to associate some + module-specific data with a specific container object. + + The exported API is best used via the wrapper macros: + + - register_TAG_data(TAG) + Get a new key for the container type TAG. + + - register_TAG_data_with_cleanup(TAG, SAVE, FREE) + Get a new key for the container type TAG. + SAVE and FREE are defined as void (*) (struct TAG *, void *) + When the container is destroyed, first all registered SAVE + functions are called. + Then all FREE functions are called. + Either or both may be NULL. + + - clear_TAG_data(TAG, OBJECT) + Clear all the data associated with OBJECT. Should be called by the + container implementation when a container object is destroyed. + + - set_TAG_data(TAG, OBJECT, KEY, DATA) + Set the data on an object. + + - TAG_data(TAG, OBJECT, KEY) + Fetch the data for an object; returns NULL if it has not been set. +*/ + +/* This structure is used in a container to hold the data that the + registry uses. */ + +struct registry_fields +{ + void **data; + unsigned num_data; +}; + +/* This macro is used in a container struct definition to define the + fields used by the registry code. */ + +#define REGISTRY_FIELDS \ + struct registry_fields registry_data + +/* A convenience macro for the typical case where the registry data is + kept as fields of the object. This can be passed as the ACCESS + method to DEFINE_REGISTRY. */ + +#define REGISTRY_ACCESS_FIELD(CONTAINER) \ + (CONTAINER) + +/* Opaque type representing a container type with a registry. This + type is never defined. This is used to factor out common + functionality of all struct tag names into common code. IOW, + "struct tag name" pointers are cast to and from "struct + registry_container" pointers when calling the common registry + "backend" functions. */ +struct registry_container; + +/* Registry callbacks have this type. */ +typedef void (*registry_data_callback) (struct registry_container *, void *); + +struct registry_data +{ + unsigned index; + registry_data_callback save; + registry_data_callback free; +}; + +struct registry_data_registration +{ + struct registry_data *data; + struct registry_data_registration *next; +}; + +struct registry_data_registry +{ + struct registry_data_registration *registrations; + unsigned num_registrations; +}; + +/* Registry backend functions. Client code uses the frontend + functions defined by DEFINE_REGISTRY below instead. */ + +const struct registry_data *register_data_with_cleanup + (struct registry_data_registry *registry, + registry_data_callback save, + registry_data_callback free); + +void registry_alloc_data (struct registry_data_registry *registry, + struct registry_fields *registry_fields); + +/* Cast FUNC and CONTAINER to the real types, and call FUNC, also + passing DATA. */ +typedef void (*registry_callback_adaptor) (registry_data_callback func, + struct registry_container *container, + void *data); + +void registry_clear_data (struct registry_data_registry *data_registry, + registry_callback_adaptor adaptor, + struct registry_container *container, + struct registry_fields *fields); + +void registry_container_free_data (struct registry_data_registry *data_registry, + registry_callback_adaptor adaptor, + struct registry_container *container, + struct registry_fields *fields); + +void registry_set_data (struct registry_fields *fields, + const struct registry_data *data, + void *value); + +void *registry_data (struct registry_fields *fields, + const struct registry_data *data); + +/* Define a new registry implementation. */ + +#define DEFINE_REGISTRY(TAG, ACCESS) \ +struct registry_data_registry TAG ## _data_registry = { NULL, 0 }; \ + \ +const struct TAG ## _data * \ +register_ ## TAG ## _data_with_cleanup (void (*save) (struct TAG *, void *), \ + void (*free) (struct TAG *, void *)) \ +{ \ + struct registry_data_registration **curr; \ + \ + return (struct TAG ## _data *) \ + register_data_with_cleanup (&TAG ## _data_registry, \ + (registry_data_callback) save, \ + (registry_data_callback) free); \ +} \ + \ +const struct TAG ## _data * \ +register_ ## TAG ## _data (void) \ +{ \ + return register_ ## TAG ## _data_with_cleanup (NULL, NULL); \ +} \ + \ +static void \ +TAG ## _alloc_data (struct TAG *container) \ +{ \ + struct registry_fields *rdata = &ACCESS (container)->registry_data; \ + \ + registry_alloc_data (&TAG ## _data_registry, rdata); \ +} \ + \ +static void \ +TAG ## registry_callback_adaptor (registry_data_callback func, \ + struct registry_container *container, \ + void *data) \ +{ \ + struct TAG *tagged_container = (struct TAG *) container; \ + struct registry_fields *rdata \ + = &ACCESS (tagged_container)->registry_data; \ + \ + registry_ ## TAG ## _callback tagged_func \ + = (registry_ ## TAG ## _callback) func; \ + \ + tagged_func (tagged_container, data); \ +} \ + \ +void \ +clear_ ## TAG ## _data (struct TAG *container) \ +{ \ + struct registry_fields *rdata = &ACCESS (container)->registry_data; \ + \ + registry_clear_data (&TAG ## _data_registry, \ + TAG ## registry_callback_adaptor, \ + (struct registry_container *) container, \ + rdata); \ +} \ + \ +static void \ +TAG ## _free_data (struct TAG *container) \ +{ \ + struct registry_fields *rdata = &ACCESS (container)->registry_data; \ + \ + registry_container_free_data (&TAG ## _data_registry, \ + TAG ## registry_callback_adaptor, \ + (struct registry_container *) container, \ + rdata); \ +} \ + \ +void \ +set_ ## TAG ## _data (struct TAG *container, \ + const struct TAG ## _data *data, \ + void *value) \ +{ \ + struct registry_fields *rdata = &ACCESS (container)->registry_data; \ + \ + registry_set_data (rdata, \ + (struct registry_data *) data, \ + value); \ +} \ + \ +void * \ +TAG ## _data (struct TAG *container, const struct TAG ## _data *data) \ +{ \ + struct registry_fields *rdata = &ACCESS (container)->registry_data; \ + \ + return registry_data (rdata, \ + (struct registry_data *) data); \ +} + + +/* External declarations for the registry functions. */ + +#define DECLARE_REGISTRY(TAG) \ +struct TAG ## _data; \ +typedef void (*registry_ ## TAG ## _callback) (struct TAG *, void *); \ +extern const struct TAG ## _data *register_ ## TAG ## _data (void); \ +extern const struct TAG ## _data *register_ ## TAG ## _data_with_cleanup \ + (registry_ ## TAG ## _callback save, registry_ ## TAG ## _callback free); \ +extern void clear_ ## TAG ## _data (struct TAG *); \ +extern void set_ ## TAG ## _data (struct TAG *, \ + const struct TAG ## _data *data, \ + void *value); \ +extern void *TAG ## _data (struct TAG *, \ + const struct TAG ## _data *data); + +#endif /* REGISTRY_H */ diff --git a/contrib/gdb-7/gdb/regset.c b/contrib/gdb-7/gdb/regset.c index af8a793b45..33a5b9b7e2 100644 --- a/contrib/gdb-7/gdb/regset.c +++ b/contrib/gdb-7/gdb/regset.c @@ -1,6 +1,6 @@ /* Manage register sets. - Copyright (C) 2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/regset.h b/contrib/gdb-7/gdb/regset.h index aabff374e3..b94afa4243 100644 --- a/contrib/gdb-7/gdb/regset.h +++ b/contrib/gdb-7/gdb/regset.h @@ -1,6 +1,6 @@ /* Manage register sets. - Copyright (C) 2003-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/remote-fileio.c b/contrib/gdb-7/gdb/remote-fileio.c index ee43dd686e..2f9d64452c 100644 --- a/contrib/gdb-7/gdb/remote-fileio.c +++ b/contrib/gdb-7/gdb/remote-fileio.c @@ -1,6 +1,6 @@ /* Remote File-I/O communications - Copyright (C) 2003, 2005-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -682,7 +682,7 @@ remote_fileio_func_read (char *buf) long target_fd, num; LONGEST lnum; CORE_ADDR ptrval; - int fd, ret, retlength; + int fd, ret; gdb_byte *buffer; size_t length; off_t old_offset, new_offset; @@ -1133,7 +1133,7 @@ static void remote_fileio_func_fstat (char *buf) { CORE_ADDR ptrval; - int fd, ret, retlength; + int fd, ret; long target_fd; LONGEST lnum; struct stat st; @@ -1212,7 +1212,7 @@ remote_fileio_func_gettimeofday (char *buf) { LONGEST lnum; CORE_ADDR ptrval; - int ret, retlength; + int ret; struct timeval tv; struct fio_timeval ftv; @@ -1281,7 +1281,7 @@ static void remote_fileio_func_system (char *buf) { CORE_ADDR ptrval; - int ret, length, retlength; + int ret, length; char *cmdline = NULL; /* Parameter: Ptr to commandline / length incl. trailing zero */ diff --git a/contrib/gdb-7/gdb/remote-fileio.h b/contrib/gdb-7/gdb/remote-fileio.h index e04d052f03..58d174b738 100644 --- a/contrib/gdb-7/gdb/remote-fileio.h +++ b/contrib/gdb-7/gdb/remote-fileio.h @@ -1,6 +1,6 @@ /* Remote File-I/O communications - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/remote-notif.c b/contrib/gdb-7/gdb/remote-notif.c new file mode 100644 index 0000000000..0f73a52c95 --- /dev/null +++ b/contrib/gdb-7/gdb/remote-notif.c @@ -0,0 +1,281 @@ +/* Remote notification in GDB protocol + + Copyright (C) 1988-2013 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 . */ + +/* Remote async notification is sent from remote target over RSP. + Each type of notification is represented by an object of + 'struct notif', which has a field 'pending_reply'. It is not + NULL when GDB receives a notification from GDBserver, but hasn't + acknowledge yet. Before GDB acknowledges the notification, + GDBserver shouldn't send notification again (see the header comments + in gdbserver/notif.c). + + Notifications are processed in an almost-unified approach for both + all-stop mode and non-stop mode, except the timing to process them. + In non-stop mode, notifications are processed in + remote_async_get_pending_events_handler, while in all-stop mode, + they are processed in remote_resume. */ + +#include "defs.h" +#include "remote.h" +#include "remote-notif.h" +#include "observer.h" +#include "event-loop.h" +#include "target.h" +#include "inferior.h" +#include "gdbcmd.h" + +#include + +int notif_debug = 0; + +/* Supported clients of notifications. */ + +static struct notif_client *notifs[] = +{ + ¬if_client_stop, +}; + +static void do_notif_event_xfree (void *arg); + +/* Parse the BUF for the expected notification NC, and send packet to + acknowledge. */ + +void +remote_notif_ack (struct notif_client *nc, char *buf) +{ + struct notif_event *event = nc->alloc_event (); + struct cleanup *old_chain + = make_cleanup (do_notif_event_xfree, event); + + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, "notif: ack '%s'\n", + nc->ack_command); + + nc->parse (nc, buf, event); + nc->ack (nc, buf, event); + + discard_cleanups (old_chain); +} + +/* Parse the BUF for the expected notification NC. */ + +struct notif_event * +remote_notif_parse (struct notif_client *nc, char *buf) +{ + struct notif_event *event = nc->alloc_event (); + struct cleanup *old_chain + = make_cleanup (do_notif_event_xfree, event); + + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, "notif: parse '%s'\n", nc->name); + + nc->parse (nc, buf, event); + + discard_cleanups (old_chain); + return event; +} + +DECLARE_QUEUE_P (notif_client_p); +DEFINE_QUEUE_P (notif_client_p); + +static QUEUE(notif_client_p) *notif_queue; + +/* Process notifications one by one. EXCEPT is not expected in + the queue. */ + +void +remote_notif_process (struct notif_client *except) +{ + while (!QUEUE_is_empty (notif_client_p, notif_queue)) + { + struct notif_client *nc = QUEUE_deque (notif_client_p, + notif_queue); + + gdb_assert (nc != except); + + if (nc->can_get_pending_events (nc)) + remote_notif_get_pending_events (nc); + } +} + +static void +remote_async_get_pending_events_handler (gdb_client_data data) +{ + gdb_assert (non_stop); + remote_notif_process (NULL); +} + +/* Asynchronous signal handle registered as event loop source for when + the remote sent us a notification. The registered callback + will do a ACK sequence to pull the rest of the events out of + the remote side into our event queue. */ + +static struct async_event_handler *remote_async_get_pending_events_token; + +/* Register async_event_handler for notification. */ + +void +remote_notif_register_async_event_handler (void) +{ + remote_async_get_pending_events_token + = create_async_event_handler (remote_async_get_pending_events_handler, + NULL); +} + +/* Unregister async_event_handler for notification. */ + +void +remote_notif_unregister_async_event_handler (void) +{ + if (remote_async_get_pending_events_token) + delete_async_event_handler (&remote_async_get_pending_events_token); +} + +/* Remote notification handler. */ + +void +handle_notification (char *buf) +{ + struct notif_client *nc = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE (notifs); i++) + { + nc = notifs[i]; + if (strncmp (buf, nc->name, strlen (nc->name)) == 0 + && buf[strlen (nc->name)] == ':') + break; + } + + /* We ignore notifications we don't recognize, for compatibility + with newer stubs. */ + if (nc == NULL) + return; + + if (nc->pending_event) + { + /* We've already parsed the in-flight reply, but the stub for some + reason thought we didn't, possibly due to timeout on its side. + Just ignore it. */ + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: ignoring resent notification\n"); + } + else + { + struct notif_event *event + = remote_notif_parse (nc, buf + strlen (nc->name) + 1); + + /* Be careful to only set it after parsing, since an error + may be thrown then. */ + nc->pending_event = event; + + /* Notify the event loop there's a stop reply to acknowledge + and that there may be more events to fetch. */ + QUEUE_enque (notif_client_p, notif_queue, nc); + if (non_stop) + { + /* In non-stop, We mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN + in order to go on what we were doing and postpone + querying notification events to some point safe to do so. + See details in the function comment of + remote.c:remote_notif_get_pending_events. + + In all-stop, GDB may be blocked to wait for the reply, we + shouldn't return to event loop until the expected reply + arrives. For example: + + 1.1) --> vCont;c + GDB expects getting stop reply 'T05 thread:2'. + 1.2) <-- %Notif + + + After step #1.2, we return to the event loop, which + notices there is a new event on the + REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and calls the + handler, which will send 'vNotif' packet. + 1.3) --> vNotif + It is not safe to start a new sequence, because target + is still running and GDB is expecting the stop reply + from stub. + + To solve this, whenever we parse a notification + successfully, we don't mark the + REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and let GDB blocked + there as before to get the sequence done. + + 2.1) --> vCont;c + GDB expects getting stop reply 'T05 thread:2' + 2.2) <-- %Notif + + 2.3) <-- T05 thread:2 + + These pending notifications can be processed later. */ + mark_async_event_handler (remote_async_get_pending_events_token); + } + + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: Notification '%s' captured\n", + nc->name); + } +} + +/* Cleanup wrapper. */ + +static void +do_notif_event_xfree (void *arg) +{ + struct notif_event *event = arg; + + if (event && event->dtr) + event->dtr (event); + + xfree (event); +} + +static void +notif_xfree (struct notif_client *notif) +{ + if (notif->pending_event != NULL + && notif->pending_event->dtr != NULL) + notif->pending_event->dtr (notif->pending_event); + + xfree (notif->pending_event); + xfree (notif); +} + +/* -Wmissing-prototypes */ +extern initialize_file_ftype _initialize_notif; + +void +_initialize_notif (void) +{ + notif_queue = QUEUE_alloc (notif_client_p, notif_xfree); + + add_setshow_boolean_cmd ("notification", no_class, ¬if_debug, + _("\ +Set debugging of async remote notification."), _("\ +Show debugging of async remote notification."), _("\ +When non-zero, debugging output about async remote notifications" +" is enabled."), + NULL, + NULL, + &setdebuglist, &showdebuglist); +} diff --git a/contrib/gdb-7/gdb/remote-notif.h b/contrib/gdb-7/gdb/remote-notif.h new file mode 100644 index 0000000000..da4fdea1ce --- /dev/null +++ b/contrib/gdb-7/gdb/remote-notif.h @@ -0,0 +1,85 @@ +/* Remote notification in GDB protocol + + Copyright (C) 1988-2013 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 REMOTE_NOTIF_H +#define REMOTE_NOTIF_H + +#include "queue.h" + +/* An event of a type of async remote notification. */ + +struct notif_event +{ + /* Destructor. Release everything from SELF, but not SELF + itself. */ + void (*dtr) (struct notif_event *self); +}; + +/* A client to a sort of async remote notification. */ + +typedef struct notif_client +{ + /* The name of notification packet. */ + const char *name; + + /* The packet to acknowledge a previous reply. */ + const char *ack_command; + + /* Parse BUF to get the expected event and update EVENT. This + function may throw exception if contents in BUF is not the + expected event. */ + void (*parse) (struct notif_client *self, char *buf, + struct notif_event *event); + + /* Send field to remote, and do some checking. If + something wrong, throw an exception. */ + void (*ack) (struct notif_client *self, char *buf, + struct notif_event *event); + + /* Check this notification client can get pending events in + 'remote_notif_process'. */ + int (*can_get_pending_events) (struct notif_client *self); + + /* Allocate an event. */ + struct notif_event *(*alloc_event) (void); + + /* One pending event. This is where we keep it until it is + acknowledged. When there is a notification packet, parse it, + and create an object of 'struct notif_event' to assign to + it. This field is unchanged until GDB starts to ack this + notification (which is done by + remote.c:remote_notif_pending_replies). */ + struct notif_event *pending_event; +} *notif_client_p; + +void remote_notif_ack (struct notif_client *nc, char *buf); +struct notif_event *remote_notif_parse (struct notif_client *nc, + char *buf); + +void handle_notification (char *buf); + +void remote_notif_register_async_event_handler (void); +void remote_notif_unregister_async_event_handler (void); + +void remote_notif_process (struct notif_client *except); +extern struct notif_client notif_client_stop; + +extern int notif_debug; + +#endif /* REMOTE_NOTIF_H */ diff --git a/contrib/gdb-7/gdb/remote.c b/contrib/gdb-7/gdb/remote.c index 04b818f8b8..7761e002aa 100644 --- a/contrib/gdb-7/gdb/remote.c +++ b/contrib/gdb-7/gdb/remote.c @@ -1,6 +1,6 @@ /* Remote target communications for serial-line targets in custom GDB protocol - Copyright (C) 1988-2012 Free Software Foundation, Inc. + Copyright (C) 1988-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -34,6 +34,7 @@ #include "gdb-stabs.h" #include "gdbthread.h" #include "remote.h" +#include "remote-notif.h" #include "regcache.h" #include "value.h" #include "gdb_assert.h" @@ -42,6 +43,7 @@ #include "cli/cli-decode.h" #include "cli/cli-setshow.h" #include "target-descriptions.h" +#include "gdb_bfd.h" #include #include @@ -65,13 +67,12 @@ #include "tracepoint.h" #include "ax.h" #include "ax-gdb.h" +#include "agent.h" +#include "btrace.h" /* Temp hacks for tracepoint encoding migration. */ static char *target_buf; static long target_buf_size; -/*static*/ void -encode_actions (struct breakpoint *t, struct bp_location *tloc, - char ***tdp_actions, char ***stepping_actions); /* The size to align memory write packets, when practical. The protocol does not guarantee any alignment, and gdb will generate short @@ -90,7 +91,7 @@ static void cleanup_sigint_signal_handler (void *dummy); static void initialize_sigint_signal_handler (void); static int getpkt_sane (char **buf, long *sizeof_buf, int forever); static int getpkt_or_notif_sane (char **buf, long *sizeof_buf, - int forever); + int forever, int *is_notif); static void handle_remote_sigint (int); static void handle_remote_sigint_twice (int); @@ -121,6 +122,8 @@ static void remote_send (char **buf, long *sizeof_buf_p); static int readchar (int timeout); +static void remote_serial_write (const char *str, int len); + static void remote_kill (struct target_ops *ops); static int tohex (int nib); @@ -183,10 +186,6 @@ static void record_currthread (ptid_t currthread); static int fromhex (int a); -extern int hex2bin (const char *hex, gdb_byte *bin, int count); - -extern int bin2hex (const gdb_byte *bin, char *hex, int count); - static int putpkt_binary (char *buf, int cnt); static void check_binary_download (CORE_ADDR addr); @@ -224,17 +223,13 @@ static void remote_check_symbols (struct objfile *objfile); void _initialize_remote (void); struct stop_reply; -static struct stop_reply *stop_reply_xmalloc (void); static void stop_reply_xfree (struct stop_reply *); -static void do_stop_reply_xfree (void *arg); -static void remote_parse_stop_reply (char *buf, struct stop_reply *); +static void remote_parse_stop_reply (char *, struct stop_reply *); static void push_stop_reply (struct stop_reply *); -static void remote_get_pending_stop_replies (void); -static void discard_pending_stop_replies (int pid); +static void discard_pending_stop_replies (struct inferior *); static int peek_stop_reply (ptid_t ptid); static void remote_async_inferior_event_handler (gdb_client_data); -static void remote_async_get_pending_events_handler (gdb_client_data); static void remote_terminal_ours (void); @@ -242,10 +237,9 @@ static int remote_read_description_p (struct target_ops *target); static void remote_console_output (char *msg); -/* The non-stop remote protocol provisions for one pending stop reply. - This is where we keep it until it is acknowledged. */ +static int remote_supports_cond_breakpoints (void); -static struct stop_reply *pending_stop_reply = NULL; +static int remote_can_run_breakpoint_commands (void); /* For "remote". */ @@ -319,6 +313,14 @@ struct remote_state /* True if the stub reports support for conditional tracepoints. */ int cond_tracepoints; + /* True if the stub reports support for target-side breakpoint + conditions. */ + int cond_breakpoints; + + /* True if the stub reports support for target-side breakpoint + commands. */ + int breakpoint_commands; + /* True if the stub reports support for fast tracepoints. */ int fast_tracepoints; @@ -363,7 +365,7 @@ free_private_thread_info (struct private_thread_info *info) static int remote_multi_process_p (struct remote_state *rs) { - return rs->extended && rs->multi_process_aware; + return rs->multi_process_aware; } /* This data could be associated with a target, but we do not always @@ -386,9 +388,9 @@ struct packet_reg long regnum; /* GDB's internal register number. */ LONGEST pnum; /* Remote protocol register number. */ int in_g_packet; /* Always part of G packet. */ - /* long size in bytes; == register_size (target_gdbarch, regnum); + /* long size in bytes; == register_size (target_gdbarch (), regnum); at present. */ - /* char *name; == gdbarch_register_name (target_gdbarch, regnum); + /* char *name; == gdbarch_register_name (target_gdbarch (), regnum); at present. */ }; @@ -430,8 +432,6 @@ trace_error (char *buf) else error (_("remote.c: error in outgoing packet at field #%ld."), strtol (buf, NULL, 16)); - case '2': - error (_("trace API error 0x%s."), ++buf); default: error (_("Target returns error code '%s'."), buf); } @@ -473,13 +473,13 @@ remote_get_noisy_reply (char **buf_p, TRY_CATCH (ex, RETURN_MASK_ALL) { - gdbarch_relocate_instruction (target_gdbarch, &to, from); + gdbarch_relocate_instruction (target_gdbarch (), &to, from); } if (ex.reason >= 0) { adjusted_size = to - org_to; - sprintf (buf, "qRelocInsn:%x", adjusted_size); + xsnprintf (buf, *sizeof_buf, "qRelocInsn:%x", adjusted_size); putpkt (buf); } else if (ex.reason < 0 && ex.error == MEMORY_ERROR) @@ -514,7 +514,7 @@ static struct gdbarch_data *remote_gdbarch_data_handle; static struct remote_arch_state * get_remote_arch_state (void) { - return gdbarch_data (target_gdbarch, remote_gdbarch_data_handle); + return gdbarch_data (target_gdbarch (), remote_gdbarch_data_handle); } /* Fetch the global remote target state. */ @@ -687,7 +687,7 @@ get_remote_packet_size (void) static struct packet_reg * packet_reg_from_regnum (struct remote_arch_state *rsa, long regnum) { - if (regnum < 0 && regnum >= gdbarch_num_regs (target_gdbarch)) + if (regnum < 0 && regnum >= gdbarch_num_regs (target_gdbarch ())) return NULL; else { @@ -703,7 +703,7 @@ packet_reg_from_pnum (struct remote_arch_state *rsa, LONGEST pnum) { int i; - for (i = 0; i < gdbarch_num_regs (target_gdbarch); i++) + for (i = 0; i < gdbarch_num_regs (target_gdbarch ()); i++) { struct packet_reg *r = &rsa->regs[i]; @@ -746,7 +746,7 @@ static int wait_forever_enabled_p = 1; const char interrupt_sequence_control_c[] = "Ctrl-C"; const char interrupt_sequence_break[] = "BREAK"; const char interrupt_sequence_break_g[] = "BREAK-g"; -static const char *interrupt_sequence_modes[] = +static const char *const interrupt_sequence_modes[] = { interrupt_sequence_control_c, interrupt_sequence_break, @@ -823,7 +823,7 @@ static struct serial *remote_desc = NULL; some remote targets this variable is principly provided to facilitate backward compatibility. */ -static int remote_address_size; +static unsigned int remote_address_size; /* Temporary to track who currently owns the terminal. See remote_terminal_* for more details. */ @@ -1242,6 +1242,7 @@ enum { PACKET_vFile_pwrite, PACKET_vFile_close, PACKET_vFile_unlink, + PACKET_vFile_readlink, PACKET_qXfer_auxv, PACKET_qXfer_features, PACKET_qXfer_libraries, @@ -1253,10 +1254,12 @@ enum { PACKET_qXfer_threads, PACKET_qXfer_statictrace_read, PACKET_qXfer_traceframe_info, + PACKET_qXfer_uib, PACKET_qGetTIBAddr, PACKET_qGetTLSAddr, PACKET_qSupported, PACKET_QPassSignals, + PACKET_QProgramSignals, PACKET_qSearch_memory, PACKET_vAttach, PACKET_vRun, @@ -1266,6 +1269,8 @@ enum { PACKET_qXfer_siginfo_write, PACKET_qAttached, PACKET_ConditionalTracepoints, + PACKET_ConditionalBreakpoints, + PACKET_BreakpointCommands, PACKET_FastTracepoints, PACKET_StaticTracepoints, PACKET_InstallInTrace, @@ -1275,6 +1280,11 @@ enum { PACKET_QAllow, PACKET_qXfer_fdpic, PACKET_QDisableRandomization, + PACKET_QAgent, + PACKET_QTBuffer_size, + PACKET_Qbtrace_off, + PACKET_Qbtrace_bts, + PACKET_qXfer_btrace, PACKET_MAX }; @@ -1385,12 +1395,6 @@ static struct async_signal_handler *sigint_remote_token; static struct async_event_handler *remote_async_inferior_event_token; -/* Asynchronous signal handle registered as event loop source for when - the remote sent us a %Stop notification. The registered callback - will do a vStopped sequence to pull the rest of the events out of - the remote side into our event queue. */ - -static struct async_event_handler *remote_async_get_pending_events_token; static ptid_t magic_null_ptid; @@ -1403,7 +1407,7 @@ static ptid_t any_thread_ptid; static ptid_t general_thread; static ptid_t continue_thread; -/* This the traceframe which we last selected on the remote system. +/* This is the traceframe which we last selected on the remote system. It will be -1 if no traceframe is selected. */ static int remote_traceframe_number = -1; @@ -1414,14 +1418,15 @@ static int remote_query_attached (int pid) { struct remote_state *rs = get_remote_state (); + size_t size = get_remote_packet_size (); if (remote_protocol_packets[PACKET_qAttached].support == PACKET_DISABLE) return 0; if (remote_multi_process_p (rs)) - sprintf (rs->buf, "qAttached:%x", pid); + xsnprintf (rs->buf, size, "qAttached:%x", pid); else - sprintf (rs->buf, "qAttached"); + xsnprintf (rs->buf, size, "qAttached"); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -1443,16 +1448,17 @@ remote_query_attached (int pid) return 0; } -/* Add PID to GDB's inferior table. Since we can be connected to a - remote system before before knowing about any inferior, mark the - target with execution when we find the first inferior. If ATTACHED - is 1, then we had just attached to this inferior. If it is 0, then - we just created this inferior. If it is -1, then try querying the - remote stub to find out if it had attached to the inferior or - not. */ +/* Add PID to GDB's inferior table. If FAKE_PID_P is true, then PID + has been invented by GDB, instead of reported by the target. Since + we can be connected to a remote system before before knowing about + any inferior, mark the target with execution when we find the first + inferior. If ATTACHED is 1, then we had just attached to this + inferior. If it is 0, then we just created this inferior. If it + is -1, then try querying the remote stub to find out if it had + attached to the inferior or not. */ static struct inferior * -remote_add_inferior (int pid, int attached) +remote_add_inferior (int fake_pid_p, int pid, int attached) { struct inferior *inf; @@ -1462,7 +1468,7 @@ remote_add_inferior (int pid, int attached) if (attached == -1) attached = remote_query_attached (pid); - if (gdbarch_has_global_solist (target_gdbarch)) + if (gdbarch_has_global_solist (target_gdbarch ())) { /* If the target shares code across all inferiors, then every attach adds a new inferior. */ @@ -1484,6 +1490,7 @@ remote_add_inferior (int pid, int attached) } inf->attach_flag = attached; + inf->fake_pid_p = fake_pid_p; return inf; } @@ -1559,7 +1566,13 @@ remote_notice_new_inferior (ptid_t currthread, int running) may not know about it yet. Add it before adding its child thread, so notifications are emitted in a sensible order. */ if (!in_inferior_list (ptid_get_pid (currthread))) - inf = remote_add_inferior (ptid_get_pid (currthread), -1); + { + struct remote_state *rs = get_remote_state (); + int fake_pid_p = !remote_multi_process_p (rs); + + inf = remote_add_inferior (fake_pid_p, + ptid_get_pid (currthread), -1); + } /* This is really a new thread. Add it. */ remote_add_thread (currthread, running); @@ -1574,7 +1587,7 @@ remote_notice_new_inferior (ptid_t currthread, int running) /* Return the private thread data, creating it if necessary. */ -struct private_thread_info * +static struct private_thread_info * demand_private_info (ptid_t ptid) { struct thread_info *info = find_thread_ptid (ptid); @@ -1657,6 +1670,65 @@ remote_pass_signals (int numsigs, unsigned char *pass_signals) } } +/* The last QProgramSignals packet sent to the target. We bypass + sending a new program signals list down to the target if the new + packet is exactly the same as the last we sent. IOW, we only let + the target know about program signals list changes. */ + +static char *last_program_signals_packet; + +/* If 'QProgramSignals' is supported, tell the remote stub what + signals it should pass through to the inferior when detaching. */ + +static void +remote_program_signals (int numsigs, unsigned char *signals) +{ + if (remote_protocol_packets[PACKET_QProgramSignals].support != PACKET_DISABLE) + { + char *packet, *p; + int count = 0, i; + + gdb_assert (numsigs < 256); + for (i = 0; i < numsigs; i++) + { + if (signals[i]) + count++; + } + packet = xmalloc (count * 3 + strlen ("QProgramSignals:") + 1); + strcpy (packet, "QProgramSignals:"); + p = packet + strlen (packet); + for (i = 0; i < numsigs; i++) + { + if (signal_pass_state (i)) + { + if (i >= 16) + *p++ = tohex (i >> 4); + *p++ = tohex (i & 15); + if (count) + *p++ = ';'; + else + break; + count--; + } + } + *p = 0; + if (!last_program_signals_packet + || strcmp (last_program_signals_packet, packet) != 0) + { + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + + putpkt (packet); + getpkt (&rs->buf, &rs->buf_size, 0); + packet_ok (buf, &remote_protocol_packets[PACKET_QProgramSignals]); + xfree (last_program_signals_packet); + last_program_signals_packet = packet; + } + else + xfree (packet); + } +} + /* If PTID is MAGIC_NULL_PTID, don't set any thread. If PTID is MINUS_ONE_PTID, set the thread to -1, so the stub returns the thread. If GEN is set, set the general thread, if not, then set @@ -1717,7 +1789,7 @@ set_general_process (void) struct remote_state *rs = get_remote_state (); /* If the remote can't handle multiple processes, don't bother. */ - if (!remote_multi_process_p (rs)) + if (!rs->extended || !remote_multi_process_p (rs)) return; /* We only need to change the remote current thread if it's pointing @@ -2688,6 +2760,15 @@ remote_threads_info (struct target_ops *ops) bufp = rs->buf; if (bufp[0] != '\0') /* q packet recognized */ { + struct cleanup *old_chain; + char *saved_reply; + + /* remote_notice_new_inferior (in the loop below) may make + new RSP calls, which clobber rs->buf. Work with a + copy. */ + bufp = saved_reply = xstrdup (rs->buf); + old_chain = make_cleanup (free_current_contents, &saved_reply); + while (*bufp++ == 'm') /* reply contains one or more TID */ { do @@ -2705,10 +2786,12 @@ remote_threads_info (struct target_ops *ops) } } while (*bufp++ == ','); /* comma-separated list */ + free_current_contents (&saved_reply); putpkt ("qsThreadInfo"); getpkt (&rs->buf, &rs->buf_size, 0); - bufp = rs->buf; + bufp = saved_reply = xstrdup (rs->buf); } + do_cleanups (old_chain); return; /* done */ } } @@ -2820,7 +2903,7 @@ remote_static_tracepoint_marker_at (CORE_ADDR addr, struct remote_state *rs = get_remote_state (); char *p = rs->buf; - sprintf (p, "qTSTMat:"); + xsnprintf (p, get_remote_packet_size (), "qTSTMat:"); p += strlen (p); p += hexnumstr (p, addr); putpkt (rs->buf); @@ -2839,20 +2922,6 @@ remote_static_tracepoint_marker_at (CORE_ADDR addr, return 0; } -static void -free_current_marker (void *arg) -{ - struct static_tracepoint_marker **marker_p = arg; - - if (*marker_p != NULL) - { - release_static_tracepoint_marker (*marker_p); - xfree (*marker_p); - } - else - *marker_p = NULL; -} - static VEC(static_tracepoint_marker_p) * remote_static_tracepoint_markers_by_strid (const char *strid) { @@ -2951,13 +3020,16 @@ remote_close (int quitting) inferior_ptid = null_ptid; discard_all_inferiors (); - /* We're no longer interested in any of these events. */ - discard_pending_stop_replies (-1); + /* Stop replies may from inferiors which are still unknown to GDB. + We are closing the remote target, so we should discard + everything, including the stop replies from GDB-unknown + inferiors. */ + discard_pending_stop_replies (NULL); if (remote_async_inferior_event_token) delete_async_event_handler (&remote_async_inferior_event_token); - if (remote_async_get_pending_events_token) - delete_async_event_handler (&remote_async_get_pending_events_token); + + remote_notif_unregister_async_event_handler (); } /* Query the remote side for the text, data and bss offsets. */ @@ -3139,13 +3211,13 @@ static void send_interrupt_sequence (void) { if (interrupt_sequence_mode == interrupt_sequence_control_c) - serial_write (remote_desc, "\x03", 1); + remote_serial_write ("\x03", 1); else if (interrupt_sequence_mode == interrupt_sequence_break) serial_send_break (remote_desc); else if (interrupt_sequence_mode == interrupt_sequence_break_g) { serial_send_break (remote_desc); - serial_write (remote_desc, "g", 1); + remote_serial_write ("g", 1); } else internal_error (__FILE__, __LINE__, @@ -3153,6 +3225,100 @@ send_interrupt_sequence (void) interrupt_sequence_mode); } + +/* If STOP_REPLY is a T stop reply, look for the "thread" register, + and extract the PTID. Returns NULL_PTID if not found. */ + +static ptid_t +stop_reply_extract_thread (char *stop_reply) +{ + if (stop_reply[0] == 'T' && strlen (stop_reply) > 3) + { + char *p; + + /* Txx r:val ; r:val (...) */ + p = &stop_reply[3]; + + /* Look for "register" named "thread". */ + while (*p != '\0') + { + char *p1; + + p1 = strchr (p, ':'); + if (p1 == NULL) + return null_ptid; + + if (strncmp (p, "thread", p1 - p) == 0) + return read_ptid (++p1, &p); + + p1 = strchr (p, ';'); + if (p1 == NULL) + return null_ptid; + p1++; + + p = p1; + } + } + + return null_ptid; +} + +/* Query the remote target for which is the current thread/process, + add it to our tables, and update INFERIOR_PTID. The caller is + responsible for setting the state such that the remote end is ready + to return the current thread. + + This function is called after handling the '?' or 'vRun' packets, + whose response is a stop reply from which we can also try + extracting the thread. If the target doesn't support the explicit + qC query, we infer the current thread from that stop reply, passed + in in WAIT_STATUS, which may be NULL. */ + +static void +add_current_inferior_and_thread (char *wait_status) +{ + struct remote_state *rs = get_remote_state (); + int fake_pid_p = 0; + ptid_t ptid = null_ptid; + + inferior_ptid = null_ptid; + + /* Now, if we have thread information, update inferior_ptid. First + if we have a stop reply handy, maybe it's a T stop reply with a + "thread" register we can extract the current thread from. If + not, ask the remote which is the current thread, with qC. The + former method avoids a roundtrip. Note we don't use + remote_parse_stop_reply as that makes use of the target + architecture, which we haven't yet fully determined at this + point. */ + if (wait_status != NULL) + ptid = stop_reply_extract_thread (wait_status); + if (ptid_equal (ptid, null_ptid)) + ptid = remote_current_thread (inferior_ptid); + + if (!ptid_equal (ptid, null_ptid)) + { + if (!remote_multi_process_p (rs)) + fake_pid_p = 1; + + inferior_ptid = ptid; + } + else + { + /* Without this, some commands which require an active target + (such as kill) won't work. This variable serves (at least) + double duty as both the pid of the target process (if it has + such), and as a flag indicating that a target is active. */ + inferior_ptid = magic_null_ptid; + fake_pid_p = 1; + } + + remote_add_inferior (fake_pid_p, ptid_get_pid (inferior_ptid), -1); + + /* Add the main thread. */ + add_thread_silent (inferior_ptid); +} + static void remote_start_remote (int from_tty, struct target_ops *target, int extended_p) { @@ -3161,6 +3327,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) char *wait_status = NULL; immediate_quit++; /* Allow user to interrupt it. */ + QUIT; if (interrupt_on_connect) send_interrupt_sequence (); @@ -3213,6 +3380,10 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) getpkt (&rs->buf, &rs->buf_size, 0); } + /* Let the target know which signals it is allowed to pass down to + the program. */ + update_signals_program_target (); + /* Next, if the target can specify a description, read it. We do this before anything involving memory or registers. */ target_find_description (); @@ -3223,7 +3394,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) /* On OSs where the list of libraries is global to all processes, we fetch them early. */ - if (gdbarch_has_global_solist (target_gdbarch)) + if (gdbarch_has_global_solist (target_gdbarch ())) solib_add (NULL, from_tty, target, auto_solib_add); if (non_stop) @@ -3247,7 +3418,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) else if (rs->non_stop_aware) { /* Don't assume that the stub can operate in all-stop mode. - Request it explicitely. */ + Request it explicitly. */ putpkt ("QNonStop:0"); getpkt (&rs->buf, &rs->buf_size, 0); @@ -3261,6 +3432,10 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) if (!non_stop) { + ptid_t ptid; + int fake_pid_p = 0; + struct inferior *inf; + if (rs->buf[0] == 'W' || rs->buf[0] == 'X') { if (!extended_p) @@ -3281,22 +3456,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) /* Let the stub know that we want it to return the thread. */ set_continue_thread (minus_one_ptid); - /* Without this, some commands which require an active target - (such as kill) won't work. This variable serves (at least) - double duty as both the pid of the target process (if it has - such), and as a flag indicating that a target is active. - These functions should be split out into seperate variables, - especially since GDB will someday have a notion of debugging - several processes. */ - inferior_ptid = magic_null_ptid; - - /* Now, if we have thread information, update inferior_ptid. */ - inferior_ptid = remote_current_thread (inferior_ptid); - - remote_add_inferior (ptid_get_pid (inferior_ptid), -1); - - /* Always add the main thread. */ - add_thread_silent (inferior_ptid); + add_current_inferior_and_thread (wait_status); /* init_wait_for_inferior should be called before get_offsets in order to manage `inserted' flag in bp loc in a correct state. @@ -3316,7 +3476,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) supported for non-stop; it could be, but it is tricky if there are no stopped threads when we connect. */ if (remote_read_description_p (target) - && gdbarch_target_desc (target_gdbarch) == NULL) + && gdbarch_target_desc (target_gdbarch ()) == NULL) { target_clear_description (); target_find_description (); @@ -3346,19 +3506,13 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) mechanism. */ if (strcmp (rs->buf, "OK") != 0) { - struct stop_reply *stop_reply; - struct cleanup *old_chain; - - stop_reply = stop_reply_xmalloc (); - old_chain = make_cleanup (do_stop_reply_xfree, stop_reply); - - remote_parse_stop_reply (rs->buf, stop_reply); - discard_cleanups (old_chain); + struct notif_client *notif = ¬if_client_stop; - /* get_pending_stop_replies acks this one, and gets the rest - out. */ - pending_stop_reply = stop_reply; - remote_get_pending_stop_replies (); + /* remote_notif_get_pending_replies acks this one, and gets + the rest out. */ + notif_client_stop.pending_event + = remote_notif_parse (notif, rs->buf); + remote_notif_get_pending_events (notif); /* Make sure that threads that were stopped remain stopped. */ @@ -3435,7 +3589,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) rs->starting_up = 0; /* If breakpoints are global, insert them now. */ - if (gdbarch_has_global_breakpoints (target_gdbarch) + if (gdbarch_has_global_breakpoints (target_gdbarch ()) && breakpoints_always_inserted_mode ()) insert_breakpoints (); } @@ -3515,12 +3669,12 @@ remote_check_symbols (struct objfile *objfile) xsnprintf (msg, get_remote_packet_size (), "qSymbol::%s", &reply[8]); else { - int addr_size = gdbarch_addr_bit (target_gdbarch) / 8; + int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8; CORE_ADDR sym_addr = SYMBOL_VALUE_ADDRESS (sym); /* If this is a function address, return the start of code instead of any data function descriptor. */ - sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, + sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), sym_addr, ¤t_target); @@ -3568,13 +3722,13 @@ remote_set_permissions (void) { struct remote_state *rs = get_remote_state (); - sprintf (rs->buf, "QAllow:" - "WriteReg:%x;WriteMem:%x;" - "InsertBreak:%x;InsertTrace:%x;" - "InsertFastTrace:%x;Stop:%x", - may_write_registers, may_write_memory, - may_insert_breakpoints, may_insert_tracepoints, - may_insert_fast_tracepoints, may_stop); + xsnprintf (rs->buf, get_remote_packet_size (), "QAllow:" + "WriteReg:%x;WriteMem:%x;" + "InsertBreak:%x;InsertTrace:%x;" + "InsertFastTrace:%x;Stop:%x", + may_write_registers, may_write_memory, + may_insert_breakpoints, may_insert_tracepoints, + may_insert_fast_tracepoints, may_stop); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -3695,6 +3849,26 @@ remote_cond_tracepoint_feature (const struct protocol_feature *feature, rs->cond_tracepoints = (support == PACKET_ENABLE); } +static void +remote_cond_breakpoint_feature (const struct protocol_feature *feature, + enum packet_support support, + const char *value) +{ + struct remote_state *rs = get_remote_state (); + + rs->cond_breakpoints = (support == PACKET_ENABLE); +} + +static void +remote_breakpoint_commands_feature (const struct protocol_feature *feature, + enum packet_support support, + const char *value) +{ + struct remote_state *rs = get_remote_state (); + + rs->breakpoint_commands = (support == PACKET_ENABLE); +} + static void remote_fast_tracepoint_feature (const struct protocol_feature *feature, enum packet_support support, @@ -3779,6 +3953,8 @@ static struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_traceframe_info }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QPassSignals }, + { "QProgramSignals", PACKET_DISABLE, remote_supported_packet, + PACKET_QProgramSignals }, { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, PACKET_QStartNoAckMode }, { "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 }, @@ -3789,6 +3965,10 @@ static struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_siginfo_write }, { "ConditionalTracepoints", PACKET_DISABLE, remote_cond_tracepoint_feature, PACKET_ConditionalTracepoints }, + { "ConditionalBreakpoints", PACKET_DISABLE, remote_cond_breakpoint_feature, + PACKET_ConditionalBreakpoints }, + { "BreakpointCommands", PACKET_DISABLE, remote_breakpoint_commands_feature, + PACKET_BreakpointCommands }, { "FastTracepoints", PACKET_DISABLE, remote_fast_tracepoint_feature, PACKET_FastTracepoints }, { "StaticTracepoints", PACKET_DISABLE, remote_static_tracepoint_feature, @@ -3809,10 +3989,19 @@ static struct protocol_feature remote_protocol_features[] = { remote_enable_disable_tracepoint_feature, -1 }, { "qXfer:fdpic:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_fdpic }, + { "qXfer:uib:read", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_uib }, { "QDisableRandomization", PACKET_DISABLE, remote_supported_packet, PACKET_QDisableRandomization }, + { "QAgent", PACKET_DISABLE, remote_supported_packet, PACKET_QAgent}, + { "QTBuffer:size", PACKET_DISABLE, + remote_supported_packet, PACKET_QTBuffer_size}, { "tracenz", PACKET_DISABLE, remote_string_tracing_feature, -1 }, + { "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off }, + { "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts }, + { "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_btrace } }; static char *remote_support_xml; @@ -3879,8 +4068,7 @@ remote_query_supported (void) char *q = NULL; struct cleanup *old_chain = make_cleanup (free_current_contents, &q); - if (rs->extended) - q = remote_query_supported_append (q, "multiprocess+"); + q = remote_query_supported_append (q, "multiprocess+"); if (remote_support_xml) q = remote_query_supported_append (q, remote_support_xml); @@ -4000,6 +4188,14 @@ remote_query_supported (void) } } +/* Remove any of the remote.c targets from target stack. Upper targets depend + on it so remove them first. */ + +static void +remote_unpush_target (void) +{ + pop_all_targets_above (process_stratum - 1, 0); +} static void remote_open_1 (char *name, int from_tty, @@ -4017,34 +4213,27 @@ remote_open_1 (char *name, int from_tty, wait_forever_enabled_p = 1; /* If we're connected to a running target, target_preopen will kill it. - But if we're connected to a target system with no running process, - then we will still be connected when it returns. Ask this question - first, before target_preopen has a chance to kill anything. */ + Ask this question first, before target_preopen has a chance to kill + anything. */ if (remote_desc != NULL && !have_inferiors ()) { - if (!from_tty - || query (_("Already connected to a remote target. Disconnect? "))) - pop_target (); - else + if (from_tty + && !query (_("Already connected to a remote target. Disconnect? "))) error (_("Still connected.")); } + /* Here the possibly existing remote target gets unpushed. */ target_preopen (from_tty); - unpush_target (target); - - /* This time without a query. If we were connected to an - extended-remote target and target_preopen killed the running - process, we may still be connected. If we are starting "target - remote" now, the extended-remote target will not have been - removed by unpush_target. */ - if (remote_desc != NULL && !have_inferiors ()) - pop_target (); - /* Make sure we send the passed signals list the next time we resume. */ xfree (last_pass_packet); last_pass_packet = NULL; + /* Make sure we send the program signals list the next time we + resume. */ + xfree (last_program_signals_packet); + last_program_signals_packet = NULL; + remote_fileio_reset (); reopen_exec_file (); reread_symbols (); @@ -4085,9 +4274,7 @@ remote_open_1 (char *name, int from_tty, remote_async_inferior_event_token = create_async_event_handler (remote_async_inferior_event_handler, NULL); - remote_async_get_pending_events_token - = create_async_event_handler (remote_async_get_pending_events_handler, - NULL); + remote_notif_register_async_event_handler (); /* Reset the target state; these things will be queried either by remote_query_supported or as they are needed. */ @@ -4157,7 +4344,7 @@ remote_open_1 (char *name, int from_tty, /* Pop the partially set up target - unless something else did already before throwing the exception. */ if (remote_desc != NULL) - pop_target (); + remote_unpush_target (); if (target_async_permitted) wait_forever_enabled_p = 1; throw_exception (ex); @@ -4185,9 +4372,19 @@ remote_detach_1 (char *args, int from_tty, int extended) if (!target_has_execution) error (_("No process to detach from.")); + if (from_tty) + { + char *exec_file = get_exec_file (0); + if (exec_file == NULL) + exec_file = ""; + printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file, + target_pid_to_str (pid_to_ptid (pid))); + gdb_flush (gdb_stdout); + } + /* Tell the remote target to detach. */ if (remote_multi_process_p (rs)) - sprintf (rs->buf, "D;%x", pid); + xsnprintf (rs->buf, get_remote_packet_size (), "D;%x", pid); else strcpy (rs->buf, "D"); @@ -4201,21 +4398,9 @@ remote_detach_1 (char *args, int from_tty, int extended) else error (_("Can't detach process.")); - if (from_tty) - { - if (remote_multi_process_p (rs)) - printf_filtered (_("Detached from remote %s.\n"), - target_pid_to_str (pid_to_ptid (pid))); - else - { - if (extended) - puts_filtered (_("Detached from remote process.\n")); - else - puts_filtered (_("Ending remote debugging.\n")); - } - } + if (from_tty && !extended) + puts_filtered (_("Ending remote debugging.\n")); - discard_pending_stop_replies (pid); target_mourn_inferior (); } @@ -4266,17 +4451,27 @@ extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty) if (remote_protocol_packets[PACKET_vAttach].support == PACKET_DISABLE) error (_("This target does not support attaching to a process")); - sprintf (rs->buf, "vAttach;%x", pid); + if (from_tty) + { + char *exec_file = get_exec_file (0); + + if (exec_file) + printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file, + target_pid_to_str (pid_to_ptid (pid))); + else + printf_unfiltered (_("Attaching to %s\n"), + target_pid_to_str (pid_to_ptid (pid))); + + gdb_flush (gdb_stdout); + } + + xsnprintf (rs->buf, get_remote_packet_size (), "vAttach;%x", pid); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vAttach]) == PACKET_OK) { - if (from_tty) - printf_unfiltered (_("Attached to %s\n"), - target_pid_to_str (pid_to_ptid (pid))); - if (!non_stop) { /* Save the reply for later. */ @@ -4294,7 +4489,7 @@ extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty) error (_("Attaching to %s failed"), target_pid_to_str (pid_to_ptid (pid))); - set_current_inferior (remote_add_inferior (pid, 1)); + set_current_inferior (remote_add_inferior (0, pid, 1)); inferior_ptid = pid_to_ptid (pid); @@ -4334,14 +4529,10 @@ extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty) if (target_can_async_p ()) { - struct stop_reply *stop_reply; - struct cleanup *old_chain; + struct notif_event *reply + = remote_notif_parse (¬if_client_stop, wait_status); - stop_reply = stop_reply_xmalloc (); - old_chain = make_cleanup (do_stop_reply_xfree, stop_reply); - remote_parse_stop_reply (wait_status, stop_reply); - discard_cleanups (old_chain); - push_stop_reply (stop_reply); + push_stop_reply ((struct stop_reply *) reply); target_async (inferior_event_handler, 0); } @@ -4487,15 +4678,15 @@ remote_vcont_probe (struct remote_state *rs) static char * append_resumption (char *p, char *endp, - ptid_t ptid, int step, enum target_signal siggnal) + ptid_t ptid, int step, enum gdb_signal siggnal) { struct remote_state *rs = get_remote_state (); - if (step && siggnal != TARGET_SIGNAL_0) + if (step && siggnal != GDB_SIGNAL_0) p += xsnprintf (p, endp - p, ";S%02x", siggnal); else if (step) p += xsnprintf (p, endp - p, ";s"); - else if (siggnal != TARGET_SIGNAL_0) + else if (siggnal != GDB_SIGNAL_0) p += xsnprintf (p, endp - p, ";C%02x", siggnal); else p += xsnprintf (p, endp - p, ";c"); @@ -4519,6 +4710,28 @@ append_resumption (char *p, char *endp, return p; } +/* Append a vCont continue-with-signal action for threads that have a + non-zero stop signal. */ + +static char * +append_pending_thread_resumptions (char *p, char *endp, ptid_t ptid) +{ + struct thread_info *thread; + + ALL_THREADS (thread) + if (ptid_match (thread->ptid, ptid) + && !ptid_equal (inferior_ptid, thread->ptid) + && thread->suspend.stop_signal != GDB_SIGNAL_0 + && signal_pass_state (thread->suspend.stop_signal)) + { + p = append_resumption (p, endp, thread->ptid, + 0, thread->suspend.stop_signal); + thread->suspend.stop_signal = GDB_SIGNAL_0; + } + + return p; +} + /* Resume the remote inferior by using a "vCont" packet. The thread to be resumed is PTID; STEP and SIGGNAL indicate whether the resumed thread should be single-stepped and/or signalled. If PTID @@ -4530,7 +4743,7 @@ append_resumption (char *p, char *endp, moment. */ static int -remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal) +remote_vcont_resume (ptid_t ptid, int step, enum gdb_signal siggnal) { struct remote_state *rs = get_remote_state (); char *p; @@ -4565,14 +4778,18 @@ remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal) process), with preference for INFERIOR_PTID. This assumes inferior_ptid belongs to the set of all threads we are about to resume. */ - if (step || siggnal != TARGET_SIGNAL_0) + if (step || siggnal != GDB_SIGNAL_0) { /* Step inferior_ptid, with or without signal. */ p = append_resumption (p, endp, inferior_ptid, step, siggnal); } + /* Also pass down any pending signaled resumption for other + threads not the current. */ + p = append_pending_thread_resumptions (p, endp, ptid); + /* And continue others without a signal. */ - append_resumption (p, endp, ptid, /*step=*/ 0, TARGET_SIGNAL_0); + append_resumption (p, endp, ptid, /*step=*/ 0, GDB_SIGNAL_0); } else { @@ -4598,17 +4815,26 @@ remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal) /* Tell the remote machine to resume. */ -static enum target_signal last_sent_signal = TARGET_SIGNAL_0; +static enum gdb_signal last_sent_signal = GDB_SIGNAL_0; static int last_sent_step; static void remote_resume (struct target_ops *ops, - ptid_t ptid, int step, enum target_signal siggnal) + ptid_t ptid, int step, enum gdb_signal siggnal) { struct remote_state *rs = get_remote_state (); char *buf; + /* In all-stop, we can't mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN + (explained in remote-notif.c:handle_notification) so + remote_notif_process is not called. We need find a place where + it is safe to start a 'vNotif' sequence. It is good to do it + before resuming inferior, because inferior was stopped and no RSP + traffic at that moment. */ + if (!non_stop) + remote_notif_process (¬if_client_stop); + last_sent_signal = siggnal; last_sent_step = step; @@ -4629,7 +4855,7 @@ remote_resume (struct target_ops *ops, if (execution_direction == EXEC_REVERSE) { /* We don't pass signals to the target in reverse exec mode. */ - if (info_verbose && siggnal != TARGET_SIGNAL_0) + if (info_verbose && siggnal != GDB_SIGNAL_0) warning (_(" - Can't pass signal %d to target in reverse: ignored."), siggnal); @@ -4642,7 +4868,7 @@ remote_resume (struct target_ops *ops, strcpy (buf, step ? "bs" : "bc"); } - else if (siggnal != TARGET_SIGNAL_0) + else if (siggnal != GDB_SIGNAL_0) { buf[0] = step ? 'S' : 'C'; buf[1] = tohex (((int) siggnal >> 4) & 0xf); @@ -4690,7 +4916,7 @@ static void handle_remote_sigint (int sig) { signal (sig, handle_remote_sigint_twice); - mark_async_signal_handler_wrapper (sigint_remote_token); + mark_async_signal_handler (sigint_remote_token); } /* Signal handler for SIGINT, installed after SIGINT has already been @@ -4700,7 +4926,7 @@ static void handle_remote_sigint_twice (int sig) { signal (sig, handle_remote_sigint); - mark_async_signal_handler_wrapper (sigint_remote_twice_token); + mark_async_signal_handler (sigint_remote_twice_token); } /* Perform the real interruption of the target execution, in response @@ -4709,7 +4935,7 @@ static void async_remote_interrupt (gdb_client_data arg) { if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n"); + fprintf_unfiltered (gdb_stdlog, "async_remote_interrupt called\n"); target_stop (inferior_ptid); } @@ -4720,7 +4946,7 @@ void async_remote_interrupt_twice (gdb_client_data arg) { if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "remote_interrupt_twice called\n"); + fprintf_unfiltered (gdb_stdlog, "async_remote_interrupt_twice called\n"); interrupt_query (); } @@ -4866,7 +5092,7 @@ interrupt_query (void) if (query (_("Interrupted while waiting for the program.\n\ Give up (and stop debugging it)? "))) { - pop_target (); + remote_unpush_target (); deprecated_throw_reason (RETURN_QUIT); } } @@ -4942,10 +5168,11 @@ typedef struct cached_reg DEF_VEC_O(cached_reg_t); -struct stop_reply +typedef struct stop_reply { - struct stop_reply *next; + struct notif_event base; + /* The identifier of the thread about this event */ ptid_t ptid; struct target_waitstatus ws; @@ -4963,19 +5190,18 @@ struct stop_reply int replay_event; int core; -}; +} *stop_reply_p; -/* The list of already fetched and acknowledged stop events. */ -static struct stop_reply *stop_reply_queue; - -static struct stop_reply * -stop_reply_xmalloc (void) -{ - struct stop_reply *r = XMALLOC (struct stop_reply); - - r->next = NULL; - return r; -} +DECLARE_QUEUE_P (stop_reply_p); +DEFINE_QUEUE_P (stop_reply_p); +/* The list of already fetched and acknowledged stop events. This + queue is used for notification Stop, and other notifications + don't need queue for their events, because the notification events + of Stop can't be consumed immediately, so that events should be + queued first, and be consumed by remote_wait_{ns,as} one per + time. Other notifications can consume their events immediately, + so queue is not needed for them. */ +static QUEUE (stop_reply_p) *stop_reply_queue; static void stop_reply_xfree (struct stop_reply *r) @@ -4987,125 +5213,226 @@ stop_reply_xfree (struct stop_reply *r) } } -/* Discard all pending stop replies of inferior PID. If PID is -1, - discard everything. */ +static void +remote_notif_stop_parse (struct notif_client *self, char *buf, + struct notif_event *event) +{ + remote_parse_stop_reply (buf, (struct stop_reply *) event); +} static void -discard_pending_stop_replies (int pid) +remote_notif_stop_ack (struct notif_client *self, char *buf, + struct notif_event *event) { - struct stop_reply *prev = NULL, *reply, *next; + struct stop_reply *stop_reply = (struct stop_reply *) event; - /* Discard the in-flight notification. */ - if (pending_stop_reply != NULL - && (pid == -1 - || ptid_get_pid (pending_stop_reply->ptid) == pid)) - { - stop_reply_xfree (pending_stop_reply); - pending_stop_reply = NULL; - } + /* acknowledge */ + putpkt ((char *) self->ack_command); - /* Discard the stop replies we have already pulled with - vStopped. */ - for (reply = stop_reply_queue; reply; reply = next) - { - next = reply->next; - if (pid == -1 - || ptid_get_pid (reply->ptid) == pid) - { - if (reply == stop_reply_queue) - stop_reply_queue = reply->next; - else - prev->next = reply->next; + if (stop_reply->ws.kind == TARGET_WAITKIND_IGNORE) + /* We got an unknown stop reply. */ + error (_("Unknown stop reply")); - stop_reply_xfree (reply); - } - else - prev = reply; - } + push_stop_reply (stop_reply); } -/* Cleanup wrapper. */ +static int +remote_notif_stop_can_get_pending_events (struct notif_client *self) +{ + /* We can't get pending events in remote_notif_process for + notification stop, and we have to do this in remote_wait_ns + instead. If we fetch all queued events from stub, remote stub + may exit and we have no chance to process them back in + remote_wait_ns. */ + mark_async_event_handler (remote_async_inferior_event_token); + return 0; +} static void -do_stop_reply_xfree (void *arg) +stop_reply_dtr (struct notif_event *event) { - struct stop_reply *r = arg; + struct stop_reply *r = (struct stop_reply *) event; - stop_reply_xfree (r); + VEC_free (cached_reg_t, r->regcache); } -/* Look for a queued stop reply belonging to PTID. If one is found, - remove it from the queue, and return it. Returns NULL if none is - found. If there are still queued events left to process, tell the - event loop to get back to target_wait soon. */ +static struct notif_event * +remote_notif_stop_alloc_reply (void) +{ + struct notif_event *r + = (struct notif_event *) XMALLOC (struct stop_reply); -static struct stop_reply * -queued_stop_reply (ptid_t ptid) + r->dtr = stop_reply_dtr; + + return r; +} + +/* A client of notification Stop. */ + +struct notif_client notif_client_stop = { - struct stop_reply *it; - struct stop_reply **it_link; + "Stop", + "vStopped", + remote_notif_stop_parse, + remote_notif_stop_ack, + remote_notif_stop_can_get_pending_events, + remote_notif_stop_alloc_reply, + NULL, +}; - it = stop_reply_queue; - it_link = &stop_reply_queue; - while (it) - { - if (ptid_match (it->ptid, ptid)) - { - *it_link = it->next; - it->next = NULL; - break; - } +/* A parameter to pass data in and out. */ - it_link = &it->next; - it = *it_link; - } +struct queue_iter_param +{ + void *input; + struct stop_reply *output; +}; - if (stop_reply_queue) - /* There's still at least an event left. */ - mark_async_event_handler (remote_async_inferior_event_token); +/* Remove all queue elements meet the condition it checks. */ - return it; +static int +remote_notif_remove_all (QUEUE (stop_reply_p) *q, + QUEUE_ITER (stop_reply_p) *iter, + stop_reply_p event, + void *data) +{ + struct queue_iter_param *param = data; + struct inferior *inf = param->input; + + if (inf == NULL || ptid_get_pid (event->ptid) == inf->pid) + { + stop_reply_xfree (event); + QUEUE_remove_elem (stop_reply_p, q, iter); + } + + return 1; } -/* Push a fully parsed stop reply in the stop reply queue. Since we - know that we now have at least one queued event left to pass to the - core side, tell the event loop to get back to target_wait soon. */ +/* Discard all pending stop replies of inferior INF. If INF is NULL, + discard everything. */ static void -push_stop_reply (struct stop_reply *new_event) +discard_pending_stop_replies (struct inferior *inf) { - struct stop_reply *event; + int i; + struct queue_iter_param param; + struct stop_reply *reply + = (struct stop_reply *) notif_client_stop.pending_event; - if (stop_reply_queue) + /* Discard the in-flight notification. */ + if (reply != NULL + && (inf == NULL + || ptid_get_pid (reply->ptid) == inf->pid)) { - for (event = stop_reply_queue; - event && event->next; - event = event->next) - ; - - event->next = new_event; + stop_reply_xfree (reply); + notif_client_stop.pending_event = NULL; } - else - stop_reply_queue = new_event; - mark_async_event_handler (remote_async_inferior_event_token); + param.input = inf; + param.output = NULL; + /* Discard the stop replies we have already pulled with + vStopped. */ + QUEUE_iterate (stop_reply_p, stop_reply_queue, + remote_notif_remove_all, ¶m); } -/* Returns true if we have a stop reply for PTID. */ +/* A parameter to pass data in and out. */ static int -peek_stop_reply (ptid_t ptid) +remote_notif_remove_once_on_match (QUEUE (stop_reply_p) *q, + QUEUE_ITER (stop_reply_p) *iter, + stop_reply_p event, + void *data) { - struct stop_reply *it; + struct queue_iter_param *param = data; + ptid_t *ptid = param->input; - for (it = stop_reply_queue; it; it = it->next) - if (ptid_equal (ptid, it->ptid)) - { - if (it->ws.kind == TARGET_WAITKIND_STOPPED) - return 1; - } + if (ptid_match (event->ptid, *ptid)) + { + param->output = event; + QUEUE_remove_elem (stop_reply_p, q, iter); + return 0; + } - return 0; + return 1; +} + +/* Remove the first reply in 'stop_reply_queue' which matches + PTID. */ + +static struct stop_reply * +remote_notif_remove_queued_reply (ptid_t ptid) +{ + struct queue_iter_param param; + + param.input = &ptid; + param.output = NULL; + + QUEUE_iterate (stop_reply_p, stop_reply_queue, + remote_notif_remove_once_on_match, ¶m); + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: discard queued event: 'Stop' in %s\n", + target_pid_to_str (ptid)); + + return param.output; +} + +/* Look for a queued stop reply belonging to PTID. If one is found, + remove it from the queue, and return it. Returns NULL if none is + found. If there are still queued events left to process, tell the + event loop to get back to target_wait soon. */ + +static struct stop_reply * +queued_stop_reply (ptid_t ptid) +{ + struct stop_reply *r = remote_notif_remove_queued_reply (ptid); + + if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue)) + /* There's still at least an event left. */ + mark_async_event_handler (remote_async_inferior_event_token); + + return r; +} + +/* Push a fully parsed stop reply in the stop reply queue. Since we + know that we now have at least one queued event left to pass to the + core side, tell the event loop to get back to target_wait soon. */ + +static void +push_stop_reply (struct stop_reply *new_event) +{ + QUEUE_enque (stop_reply_p, stop_reply_queue, new_event); + + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: push 'Stop' %s to queue %d\n", + target_pid_to_str (new_event->ptid), + QUEUE_length (stop_reply_p, + stop_reply_queue)); + + mark_async_event_handler (remote_async_inferior_event_token); +} + +static int +stop_reply_match_ptid_and_ws (QUEUE (stop_reply_p) *q, + QUEUE_ITER (stop_reply_p) *iter, + struct stop_reply *event, + void *data) +{ + ptid_t *ptid = data; + + return !(ptid_equal (*ptid, event->ptid) + && event->ws.kind == TARGET_WAITKIND_STOPPED); +} + +/* Returns true if we have a stop reply for PTID. */ + +static int +peek_stop_reply (ptid_t ptid) +{ + return !QUEUE_iterate (stop_reply_p, stop_reply_queue, + stop_reply_match_ptid_and_ws, &ptid); } /* Parse the stop reply in BUF. Either the function succeeds, and the @@ -5235,10 +5562,10 @@ Packet: '%s'\n"), cached_reg.num = reg->regnum; fieldsize = hex2bin (p, cached_reg.data, - register_size (target_gdbarch, + register_size (target_gdbarch (), reg->regnum)); p += 2 * fieldsize; - if (fieldsize < register_size (target_gdbarch, + if (fieldsize < register_size (target_gdbarch (), reg->regnum)) warning (_("Remote reply is too short: %s"), buf); @@ -5259,7 +5586,7 @@ Packet: '%s'\n"), else { event->ws.kind = TARGET_WAITKIND_STOPPED; - event->ws.value.sig = (enum target_signal) + event->ws.value.sig = (enum gdb_signal) (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); } break; @@ -5285,7 +5612,7 @@ Packet: '%s'\n"), { /* The remote process exited with a signal. */ event->ws.kind = TARGET_WAITKIND_SIGNALLED; - event->ws.value.sig = (enum target_signal) value; + event->ws.value.sig = (enum gdb_signal) value; } /* If no process is specified, assume inferior_ptid. */ @@ -5321,13 +5648,14 @@ Packet: '%s'\n"), error (_("No process or thread specified in stop reply: %s"), buf); } -/* When the stub wants to tell GDB about a new stop reply, it sends a - stop notification (%Stop). Those can come it at any time, hence, - we have to make sure that any pending putpkt/getpkt sequence we're - making is finished, before querying the stub for more events with - vStopped. E.g., if we started a vStopped sequence immediatelly - upon receiving the %Stop notification, something like this could - happen: +/* When the stub wants to tell GDB about a new notification reply, it + sends a notification (%Stop, for example). Those can come it at + any time, hence, we have to make sure that any pending + putpkt/getpkt sequence we're making is finished, before querying + the stub for more events with the corresponding ack command + (vStopped, for example). E.g., if we started a vStopped sequence + immediately upon receiving the notification, something like this + could happen: 1.1) --> Hg 1 1.2) <-- OK @@ -5339,7 +5667,7 @@ Packet: '%s'\n"), Obviously, the reply in step #1.6 would be unexpected to a vStopped query. - To solve this, whenever we parse a %Stop notification sucessfully, + To solve this, whenever we parse a %Stop notification successfully, we mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN, and carry on doing whatever we were doing: @@ -5362,19 +5690,21 @@ Packet: '%s'\n"), 2.9) --> OK */ -static void -remote_get_pending_stop_replies (void) +void +remote_notif_get_pending_events (struct notif_client *nc) { struct remote_state *rs = get_remote_state (); - if (pending_stop_reply) + if (nc->pending_event) { - /* acknowledge */ - putpkt ("vStopped"); + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: process: '%s' ack pending event\n", + nc->name); - /* Now we can rely on it. */ - push_stop_reply (pending_stop_reply); - pending_stop_reply = NULL; + /* acknowledge */ + nc->ack (nc, rs->buf, nc->pending_event); + nc->pending_event = NULL; while (1) { @@ -5382,31 +5712,18 @@ remote_get_pending_stop_replies (void) if (strcmp (rs->buf, "OK") == 0) break; else - { - struct cleanup *old_chain; - struct stop_reply *stop_reply = stop_reply_xmalloc (); - - old_chain = make_cleanup (do_stop_reply_xfree, stop_reply); - remote_parse_stop_reply (rs->buf, stop_reply); - - /* acknowledge */ - putpkt ("vStopped"); - - if (stop_reply->ws.kind != TARGET_WAITKIND_IGNORE) - { - /* Now we can rely on it. */ - discard_cleanups (old_chain); - push_stop_reply (stop_reply); - } - else - /* We got an unknown stop reply. */ - do_cleanups (old_chain); - } + remote_notif_ack (nc, rs->buf); } } + else + { + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: process: '%s' no pending reply\n", + nc->name); + } } - /* Called when it is decided that STOP_REPLY holds the info of the event that is to be returned to the core. This function always destroys STOP_REPLY. */ @@ -5432,7 +5749,7 @@ process_stop_reply (struct stop_reply *stop_reply, if (stop_reply->regcache) { struct regcache *regcache - = get_thread_arch_regcache (ptid, target_gdbarch); + = get_thread_arch_regcache (ptid, target_gdbarch ()); cached_reg_t *reg; int ix; @@ -5462,15 +5779,16 @@ remote_wait_ns (ptid_t ptid, struct target_waitstatus *status, int options) struct remote_state *rs = get_remote_state (); struct stop_reply *stop_reply; int ret; + int is_notif = 0; /* If in non-stop mode, get out of getpkt even if a notification is received. */ ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size, - 0 /* forever */); + 0 /* forever */, &is_notif); while (1) { - if (ret != -1) + if (ret != -1 && !is_notif) switch (rs->buf[0]) { case 'E': /* Error of some sort. */ @@ -5489,8 +5807,8 @@ remote_wait_ns (ptid_t ptid, struct target_waitstatus *status, int options) /* Acknowledge a pending stop reply that may have arrived in the mean time. */ - if (pending_stop_reply != NULL) - remote_get_pending_stop_replies (); + if (notif_client_stop.pending_event != NULL) + remote_notif_get_pending_events (¬if_client_stop); /* If indeed we noticed a stop reply, we're done. */ stop_reply = queued_stop_reply (ptid); @@ -5507,7 +5825,7 @@ remote_wait_ns (ptid_t ptid, struct target_waitstatus *status, int options) /* Otherwise do a blocking wait. */ ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size, - 1 /* forever */); + 1 /* forever */, &is_notif); } } @@ -5537,15 +5855,16 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options) else { int ret; + int is_notif; if (!target_is_async_p ()) { ofunc = signal (SIGINT, remote_interrupt); /* If the user hit C-c before this packet, or between packets, pretend that it was hit right here. */ - if (quit_flag) + if (check_quit_flag ()) { - quit_flag = 0; + clear_quit_flag (); remote_interrupt (SIGINT); } } @@ -5554,7 +5873,14 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options) _never_ wait for ever -> test on target_is_async_p(). However, before we do that we need to ensure that the caller knows how to take the target into/out of async mode. */ - ret = getpkt_sane (&rs->buf, &rs->buf_size, wait_forever_enabled_p); + ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size, + wait_forever_enabled_p, &is_notif); + + /* GDB gets a notification. Return to core as this event is + not interesting. */ + if (ret != -1 && is_notif) + return minus_one_ptid; + if (!target_is_async_p ()) signal (SIGINT, ofunc); } @@ -5578,7 +5904,7 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options) not? Not is more likely, so report a stop. */ warning (_("Remote failure reply: %s"), buf); status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = TARGET_SIGNAL_0; + status->value.sig = GDB_SIGNAL_0; break; case 'F': /* File-I/O request. */ remote_fileio_request (buf, rs->ctrlc_pending_p); @@ -5586,13 +5912,10 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options) break; case 'T': case 'S': case 'X': case 'W': { - struct stop_reply *stop_reply; - struct cleanup *old_chain; + struct stop_reply *stop_reply + = (struct stop_reply *) remote_notif_parse (¬if_client_stop, + rs->buf); - stop_reply = stop_reply_xmalloc (); - old_chain = make_cleanup (do_stop_reply_xfree, stop_reply); - remote_parse_stop_reply (buf, stop_reply); - discard_cleanups (old_chain); event_ptid = process_stop_reply (stop_reply, status); break; } @@ -5604,15 +5927,15 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options) break; case '\0': - if (last_sent_signal != TARGET_SIGNAL_0) + if (last_sent_signal != GDB_SIGNAL_0) { /* Zero length reply means that we tried 'S' or 'C' and the remote system doesn't support it. */ target_terminal_ours_for_output (); printf_filtered ("Can't send signals to this remote system. %s not sent.\n", - target_signal_to_name (last_sent_signal)); - last_sent_signal = TARGET_SIGNAL_0; + gdb_signal_to_name (last_sent_signal)); + last_sent_signal = GDB_SIGNAL_0; target_terminal_inferior (); strcpy ((char *) buf, last_sent_step ? "s" : "c"); @@ -5673,7 +5996,7 @@ remote_wait (struct target_ops *ops, { /* If there are are events left in the queue tell the event loop to return here. */ - if (stop_reply_queue) + if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue)) mark_async_event_handler (remote_async_inferior_event_token); } @@ -5748,7 +6071,7 @@ send_g_packet (void) struct remote_state *rs = get_remote_state (); int buf_len; - sprintf (rs->buf, "g"); + xsnprintf (rs->buf, get_remote_packet_size (), "g"); remote_send (&rs->buf, &rs->buf_size); /* We can get out of synch in various cases. If the first character @@ -6142,11 +6465,11 @@ hexnumnstr (char *buf, ULONGEST num, int width) static CORE_ADDR remote_address_masked (CORE_ADDR addr) { - int address_size = remote_address_size; + unsigned int address_size = remote_address_size; /* If "remoteaddresssize" was not set, default to target address size. */ if (!address_size) - address_size = gdbarch_addr_bit (target_gdbarch); + address_size = gdbarch_addr_bit (target_gdbarch ()); if (address_size > 0 && address_size < (sizeof (ULONGEST) * 8)) @@ -6325,7 +6648,7 @@ check_binary_download (CORE_ADDR addr) static int remote_write_bytes_aux (const char *header, CORE_ADDR memaddr, - const gdb_byte *myaddr, int len, + const gdb_byte *myaddr, ssize_t len, char packet_format, int use_length) { struct remote_state *rs = get_remote_state (); @@ -6486,7 +6809,7 @@ remote_write_bytes_aux (const char *header, CORE_ADDR memaddr, error. Only transfer a single packet. */ static int -remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len) +remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) { char *packet_format = 0; @@ -6568,51 +6891,6 @@ remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len) /* Return what we have. Let higher layers handle partial reads. */ return i; } - - -/* Remote notification handler. */ - -static void -handle_notification (char *buf, size_t length) -{ - if (strncmp (buf, "Stop:", 5) == 0) - { - if (pending_stop_reply) - { - /* We've already parsed the in-flight stop-reply, but the - stub for some reason thought we didn't, possibly due to - timeout on its side. Just ignore it. */ - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "ignoring resent notification\n"); - } - else - { - struct cleanup *old_chain; - struct stop_reply *reply = stop_reply_xmalloc (); - - old_chain = make_cleanup (do_stop_reply_xfree, reply); - - remote_parse_stop_reply (buf + 5, reply); - - discard_cleanups (old_chain); - - /* Be careful to only set it after parsing, since an error - may be thrown then. */ - pending_stop_reply = reply; - - /* Notify the event loop there's a stop reply to acknowledge - and that there may be more events to fetch. */ - mark_async_event_handler (remote_async_get_pending_events_token); - - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "stop notification captured\n"); - } - } - else - /* We ignore notifications we don't recognize, for compatibility - with newer stubs. */ - ; -} /* Read or write LEN bytes from inferior memory at MEMADDR, @@ -6681,7 +6959,7 @@ static void remote_flash_erase (struct target_ops *ops, ULONGEST address, LONGEST length) { - int addr_size = gdbarch_addr_bit (target_gdbarch) / 8; + int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8; int saved_remote_timeout = remote_timeout; enum packet_result ret; struct cleanup *back_to = make_cleanup (restore_remote_timeout, @@ -6769,13 +7047,14 @@ readchar (int timeout) switch ((enum serial_rc) ch) { case SERIAL_EOF: - pop_target (); - error (_("Remote connection closed")); + remote_unpush_target (); + throw_error (TARGET_CLOSE_ERROR, _("Remote connection closed")); /* no return */ case SERIAL_ERROR: - pop_target (); - perror_with_name (_("Remote communication error. " - "Target disconnected.")); + remote_unpush_target (); + throw_perror_with_name (TARGET_CLOSE_ERROR, + _("Remote communication error. " + "Target disconnected.")); /* no return */ case SERIAL_TIMEOUT: break; @@ -6783,6 +7062,21 @@ readchar (int timeout) return ch; } +/* Wrapper for serial_write that closes the target and throws if + writing fails. */ + +static void +remote_serial_write (const char *str, int len) +{ + if (serial_write (remote_desc, str, len)) + { + remote_unpush_target (); + throw_perror_with_name (TARGET_CLOSE_ERROR, + _("Remote communication error. " + "Target disconnected.")); + } +} + /* Send the command in *BUF to the remote machine, and read the reply into *BUF. Report an error if we get an error reply. Resize *BUF using xrealloc if necessary to hold the result, and update @@ -6854,6 +7148,7 @@ putpkt_binary (char *buf, int cnt) int ch; int tcount = 0; char *p; + char *message; /* Catch cases like trying to read memory or listing threads while we're waiting for a stop reply. The remote server wouldn't be @@ -6902,8 +7197,7 @@ putpkt_binary (char *buf, int cnt) gdb_flush (gdb_stdlog); do_cleanups (old_chain); } - if (serial_write (remote_desc, buf2, p - buf2)) - perror_with_name (_("putpkt: write failed")); + remote_serial_write (buf2, p - buf2); /* If this is a no acks version of the remote protocol, send the packet and move on. */ @@ -6958,7 +7252,7 @@ putpkt_binary (char *buf, int cnt) doesn't get retransmitted when we resend this packet. */ skip_frame (); - serial_write (remote_desc, "+", 1); + remote_serial_write ("+", 1); continue; /* Now, go look for +. */ } @@ -6985,7 +7279,7 @@ putpkt_binary (char *buf, int cnt) str); do_cleanups (old_chain); } - handle_notification (rs->buf, val); + handle_notification (rs->buf); /* We're in sync now, rewait for the ack. */ tcount = 0; } @@ -7236,11 +7530,13 @@ getpkt (char **buf, 0, this function is allowed to time out gracefully and return an indication of this to the caller. Otherwise return the number of bytes read. If EXPECTING_NOTIF, consider receiving a notification - enough reason to return to the caller. */ + enough reason to return to the caller. *IS_NOTIF is an output + boolean that indicates whether *BUF holds a notification or not + (a regular packet). */ static int getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever, - int expecting_notif) + int expecting_notif, int *is_notif) { struct remote_state *rs = get_remote_state (); int c; @@ -7294,8 +7590,10 @@ getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever, if (forever) /* Watchdog went off? Kill the target. */ { QUIT; - pop_target (); - error (_("Watchdog timeout has expired. Target detached.")); + remote_unpush_target (); + throw_error (TARGET_CLOSE_ERROR, + _("Watchdog timeout has expired. " + "Target detached.")); } if (remote_debug) fputs_filtered ("Timed out.\n", gdb_stdlog); @@ -7309,7 +7607,7 @@ getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever, break; } - serial_write (remote_desc, "-", 1); + remote_serial_write ("-", 1); } if (tries > MAX_TRIES) @@ -7320,7 +7618,7 @@ getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever, /* Skip the ack char if we're in no-ack mode. */ if (!rs->noack_mode) - serial_write (remote_desc, "+", 1); + remote_serial_write ("+", 1); return -1; } @@ -7340,7 +7638,9 @@ getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever, /* Skip the ack char if we're in no-ack mode. */ if (!rs->noack_mode) - serial_write (remote_desc, "+", 1); + remote_serial_write ("+", 1); + if (is_notif != NULL) + *is_notif = 0; return val; } @@ -7362,13 +7662,15 @@ getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever, str); do_cleanups (old_chain); } + if (is_notif != NULL) + *is_notif = 1; - handle_notification (*buf, val); + handle_notification (*buf); /* Notifications require no acknowledgement. */ if (expecting_notif) - return -1; + return val; } } } @@ -7376,13 +7678,15 @@ getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever, static int getpkt_sane (char **buf, long *sizeof_buf, int forever) { - return getpkt_or_notif_sane_1 (buf, sizeof_buf, forever, 0); + return getpkt_or_notif_sane_1 (buf, sizeof_buf, forever, 0, NULL); } static int -getpkt_or_notif_sane (char **buf, long *sizeof_buf, int forever) +getpkt_or_notif_sane (char **buf, long *sizeof_buf, int forever, + int *is_notif) { - return getpkt_or_notif_sane_1 (buf, sizeof_buf, forever, 1); + return getpkt_or_notif_sane_1 (buf, sizeof_buf, forever, 1, + is_notif); } @@ -7413,7 +7717,7 @@ remote_vkill (int pid, struct remote_state *rs) return -1; /* Tell the remote target to detach. */ - sprintf (rs->buf, "vKill;%x", pid); + xsnprintf (rs->buf, get_remote_packet_size (), "vKill;%x", pid); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -7434,7 +7738,7 @@ extended_remote_kill (struct target_ops *ops) struct remote_state *rs = get_remote_state (); res = remote_vkill (pid, rs); - if (res == -1 && !remote_multi_process_p (rs)) + if (res == -1 && !(rs->extended && remote_multi_process_p (rs))) { /* Don't try 'k' on a multi-process aware stub -- it has no way to specify the pid. */ @@ -7482,9 +7786,6 @@ extended_remote_mourn_1 (struct target_ops *target) connected. */ rs->waiting_for_stop_reply = 0; - /* We're no longer interested in these events. */ - discard_pending_stop_replies (ptid_get_pid (inferior_ptid)); - /* If the current general thread belonged to the process we just detached from or has exited, the remote side current general thread becomes undefined. Considering a case like this: @@ -7556,7 +7857,8 @@ extended_remote_disable_randomization (int val) struct remote_state *rs = get_remote_state (); char *reply; - sprintf (rs->buf, "QDisableRandomization:%x", val); + xsnprintf (rs->buf, get_remote_packet_size (), "QDisableRandomization:%x", + val); putpkt (rs->buf); reply = remote_get_noisy_reply (&target_buf, &target_buf_size); if (*reply == '\0') @@ -7609,7 +7911,7 @@ extended_remote_run (char *args) if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vRun]) == PACKET_OK) { - /* We have a wait response; we don't need it, though. All is well. */ + /* We have a wait response. All is well. */ return 0; } else if (remote_protocol_packets[PACKET_vRun].support == PACKET_DISABLE) @@ -7636,6 +7938,10 @@ static void extended_remote_create_inferior_1 (char *exec_file, char *args, char **env, int from_tty) { + int run_worked; + char *stop_reply; + struct remote_state *rs = get_remote_state (); + /* If running asynchronously, register the target file descriptor with the event loop. */ if (target_can_async_p ()) @@ -7646,7 +7952,8 @@ extended_remote_create_inferior_1 (char *exec_file, char *args, extended_remote_disable_randomization (disable_randomization); /* Now restart the remote server. */ - if (extended_remote_run (args) == -1) + run_worked = extended_remote_run (args) != -1; + if (!run_worked) { /* vRun was not supported. Fail if we need it to do what the user requested. */ @@ -7668,14 +7975,9 @@ extended_remote_create_inferior_1 (char *exec_file, char *args, init_wait_for_inferior (); } - /* Now mark the inferior as running before we do anything else. */ - inferior_ptid = magic_null_ptid; - - /* Now, if we have thread information, update inferior_ptid. */ - inferior_ptid = remote_current_thread (inferior_ptid); - - remote_add_inferior (ptid_get_pid (inferior_ptid), 0); - add_thread_silent (inferior_ptid); + /* vRun's success return is a stop reply. */ + stop_reply = run_worked ? rs->buf : NULL; + add_current_inferior_and_thread (stop_reply); /* Get updated offsets, if the stub uses qOffsets. */ get_offsets (); @@ -7690,6 +7992,75 @@ extended_remote_create_inferior (struct target_ops *ops, } +/* Given a location's target info BP_TGT and the packet buffer BUF, output + the list of conditions (in agent expression bytecode format), if any, the + target needs to evaluate. The output is placed into the packet buffer + started from BUF and ended at BUF_END. */ + +static int +remote_add_target_side_condition (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt, char *buf, + char *buf_end) +{ + struct agent_expr *aexpr = NULL; + int i, ix; + char *pkt; + char *buf_start = buf; + + if (VEC_empty (agent_expr_p, bp_tgt->conditions)) + return 0; + + buf += strlen (buf); + xsnprintf (buf, buf_end - buf, "%s", ";"); + buf++; + + /* Send conditions to the target and free the vector. */ + for (ix = 0; + VEC_iterate (agent_expr_p, bp_tgt->conditions, ix, aexpr); + ix++) + { + xsnprintf (buf, buf_end - buf, "X%x,", aexpr->len); + buf += strlen (buf); + for (i = 0; i < aexpr->len; ++i) + buf = pack_hex_byte (buf, aexpr->buf[i]); + *buf = '\0'; + } + + VEC_free (agent_expr_p, bp_tgt->conditions); + return 0; +} + +static void +remote_add_target_side_commands (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt, char *buf) +{ + struct agent_expr *aexpr = NULL; + int i, ix; + + if (VEC_empty (agent_expr_p, bp_tgt->tcommands)) + return; + + buf += strlen (buf); + + sprintf (buf, ";cmds:%x,", bp_tgt->persist); + buf += strlen (buf); + + /* Concatenate all the agent expressions that are commands into the + cmds parameter. */ + for (ix = 0; + VEC_iterate (agent_expr_p, bp_tgt->tcommands, ix, aexpr); + ix++) + { + sprintf (buf, "X%x,", aexpr->len); + buf += strlen (buf); + for (i = 0; i < aexpr->len; ++i) + buf = pack_hex_byte (buf, aexpr->buf[i]); + *buf = '\0'; + } + + VEC_free (agent_expr_p, bp_tgt->tcommands); +} + /* Insert a breakpoint. On targets that have software breakpoint support, we ask the remote target to do the work; on targets which don't, we insert a traditional memory breakpoint. */ @@ -7707,20 +8078,28 @@ remote_insert_breakpoint (struct gdbarch *gdbarch, { CORE_ADDR addr = bp_tgt->placed_address; struct remote_state *rs; - char *p; + char *p, *endbuf; int bpsize; + struct condition_list *cond = NULL; gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize); rs = get_remote_state (); p = rs->buf; + endbuf = rs->buf + get_remote_packet_size (); *(p++) = 'Z'; *(p++) = '0'; *(p++) = ','; addr = (ULONGEST) remote_address_masked (addr); p += hexnumstr (p, addr); - sprintf (p, ",%d", bpsize); + xsnprintf (p, endbuf - p, ",%d", bpsize); + + if (remote_supports_cond_breakpoints ()) + remote_add_target_side_condition (gdbarch, bp_tgt, p, endbuf); + + if (remote_can_run_breakpoint_commands ()) + remote_add_target_side_commands (gdbarch, bp_tgt, p); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -7751,6 +8130,7 @@ remote_remove_breakpoint (struct gdbarch *gdbarch, if (remote_protocol_packets[PACKET_Z0].support != PACKET_DISABLE) { char *p = rs->buf; + char *endbuf = rs->buf + get_remote_packet_size (); *(p++) = 'z'; *(p++) = '0'; @@ -7758,7 +8138,7 @@ remote_remove_breakpoint (struct gdbarch *gdbarch, addr = (ULONGEST) remote_address_masked (bp_tgt->placed_address); p += hexnumstr (p, addr); - sprintf (p, ",%d", bp_tgt->placed_size); + xsnprintf (p, endbuf - p, ",%d", bp_tgt->placed_size); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -7794,17 +8174,18 @@ remote_insert_watchpoint (CORE_ADDR addr, int len, int type, struct expression *cond) { struct remote_state *rs = get_remote_state (); + char *endbuf = rs->buf + get_remote_packet_size (); char *p; enum Z_packet_type packet = watchpoint_to_Z_packet (type); if (remote_protocol_packets[PACKET_Z0 + packet].support == PACKET_DISABLE) return 1; - sprintf (rs->buf, "Z%x,", packet); + xsnprintf (rs->buf, endbuf - rs->buf, "Z%x,", packet); p = strchr (rs->buf, '\0'); addr = remote_address_masked (addr); p += hexnumstr (p, (ULONGEST) addr); - sprintf (p, ",%x", len); + xsnprintf (p, endbuf - p, ",%x", len); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -7822,23 +8203,33 @@ remote_insert_watchpoint (CORE_ADDR addr, int len, int type, _("remote_insert_watchpoint: reached end of function")); } +static int +remote_watchpoint_addr_within_range (struct target_ops *target, CORE_ADDR addr, + CORE_ADDR start, int length) +{ + CORE_ADDR diff = remote_address_masked (addr - start); + + return diff < length; +} + static int remote_remove_watchpoint (CORE_ADDR addr, int len, int type, struct expression *cond) { struct remote_state *rs = get_remote_state (); + char *endbuf = rs->buf + get_remote_packet_size (); char *p; enum Z_packet_type packet = watchpoint_to_Z_packet (type); if (remote_protocol_packets[PACKET_Z0 + packet].support == PACKET_DISABLE) return -1; - sprintf (rs->buf, "z%x,", packet); + xsnprintf (rs->buf, endbuf - rs->buf, "z%x,", packet); p = strchr (rs->buf, '\0'); addr = remote_address_masked (addr); p += hexnumstr (p, (ULONGEST) addr); - sprintf (p, ",%x", len); + xsnprintf (p, endbuf - p, ",%x", len); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -7925,7 +8316,8 @@ remote_insert_hw_breakpoint (struct gdbarch *gdbarch, { CORE_ADDR addr; struct remote_state *rs; - char *p; + char *p, *endbuf; + char *message; /* The length field should be set to the size of a breakpoint instruction, even though we aren't inserting one ourselves. */ @@ -7938,6 +8330,7 @@ remote_insert_hw_breakpoint (struct gdbarch *gdbarch, rs = get_remote_state (); p = rs->buf; + endbuf = rs->buf + get_remote_packet_size (); *(p++) = 'Z'; *(p++) = '1'; @@ -7945,7 +8338,13 @@ remote_insert_hw_breakpoint (struct gdbarch *gdbarch, addr = remote_address_masked (bp_tgt->placed_address); p += hexnumstr (p, (ULONGEST) addr); - sprintf (p, ",%x", bp_tgt->placed_size); + xsnprintf (p, endbuf - p, ",%x", bp_tgt->placed_size); + + if (remote_supports_cond_breakpoints ()) + remote_add_target_side_condition (gdbarch, bp_tgt, p, endbuf); + + if (remote_can_run_breakpoint_commands ()) + remote_add_target_side_commands (gdbarch, bp_tgt, p); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -7953,6 +8352,13 @@ remote_insert_hw_breakpoint (struct gdbarch *gdbarch, switch (packet_ok (rs->buf, &remote_protocol_packets[PACKET_Z1])) { case PACKET_ERROR: + if (rs->buf[1] == '.') + { + message = strchr (rs->buf + 2, '.'); + if (message) + error (_("Remote failure reply: %s"), message + 1); + } + return -1; case PACKET_UNKNOWN: return -1; case PACKET_OK: @@ -7970,6 +8376,7 @@ remote_remove_hw_breakpoint (struct gdbarch *gdbarch, CORE_ADDR addr; struct remote_state *rs = get_remote_state (); char *p = rs->buf; + char *endbuf = rs->buf + get_remote_packet_size (); if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE) return -1; @@ -7980,7 +8387,7 @@ remote_remove_hw_breakpoint (struct gdbarch *gdbarch, addr = remote_address_masked (bp_tgt->placed_address); p += hexnumstr (p, (ULONGEST) addr); - sprintf (p, ",%x", bp_tgt->placed_size); + xsnprintf (p, endbuf - p, ",%x", bp_tgt->placed_size); putpkt (rs->buf); getpkt (&rs->buf, &rs->buf_size, 0); @@ -8105,12 +8512,12 @@ compare_sections_command (char *args, int from_tty) if (res == -1) error (_("target memory fault, section %s, range %s -- %s"), sectname, - paddress (target_gdbarch, lma), - paddress (target_gdbarch, lma + size)); + paddress (target_gdbarch (), lma), + paddress (target_gdbarch (), lma + size)); printf_filtered ("Section %s, range %s -- %s: ", sectname, - paddress (target_gdbarch, lma), - paddress (target_gdbarch, lma + size)); + paddress (target_gdbarch (), lma), + paddress (target_gdbarch (), lma + size)); if (res) printf_filtered ("matched.\n"); else @@ -8404,6 +8811,15 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object, case TARGET_OBJECT_FDPIC: return remote_read_qxfer (ops, "fdpic", annex, readbuf, offset, len, &remote_protocol_packets[PACKET_qXfer_fdpic]); + + case TARGET_OBJECT_OPENVMS_UIB: + return remote_read_qxfer (ops, "uib", annex, readbuf, offset, len, + &remote_protocol_packets[PACKET_qXfer_uib]); + + case TARGET_OBJECT_BTRACE: + return remote_read_qxfer (ops, "btrace", annex, readbuf, offset, len, + &remote_protocol_packets[PACKET_qXfer_btrace]); + default: return -1; } @@ -8461,7 +8877,7 @@ remote_search_memory (struct target_ops* ops, const gdb_byte *pattern, ULONGEST pattern_len, CORE_ADDR *found_addrp) { - int addr_size = gdbarch_addr_bit (target_gdbarch) / 8; + int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8; struct remote_state *rs = get_remote_state (); int max_size = get_memory_write_packet_size (); struct packet_config *packet = @@ -8577,8 +8993,17 @@ remote_rcmd (char *command, char *buf; /* XXX - see also remote_get_noisy_reply(). */ + QUIT; /* Allow user to bail out with ^C. */ rs->buf[0] = '\0'; - getpkt (&rs->buf, &rs->buf_size, 0); + if (getpkt_sane (&rs->buf, &rs->buf_size, 0) == -1) + { + /* Timeout. Continue to (try to) read responses. + This is better than stopping with an error, assuming the stub + is still executing the (long) monitor command. + If needed, the user can interrupt gdb using C-c, obtaining + an effect similar to stop on timeout. */ + continue; + } buf = rs->buf; if (buf[0] == '\0') error (_("Target does not support this command.")); @@ -8801,7 +9226,9 @@ remote_pid_to_str (struct target_ops *ops, ptid_t ptid) static char buf[64]; struct remote_state *rs = get_remote_state (); - if (ptid_is_pid (ptid)) + if (ptid_equal (ptid, null_ptid)) + return normal_pid_to_str (ptid); + else if (ptid_is_pid (ptid)) { /* Printing an inferior target id. */ @@ -8826,7 +9253,7 @@ remote_pid_to_str (struct target_ops *ops, ptid_t ptid) { if (ptid_equal (magic_null_ptid, ptid)) xsnprintf (buf, sizeof buf, "Thread
"); - else if (remote_multi_process_p (rs)) + else if (rs->extended && remote_multi_process_p (rs)) xsnprintf (buf, sizeof buf, "Thread %d.%ld", ptid_get_pid (ptid), ptid_get_tid (ptid)); else @@ -8887,7 +9314,7 @@ remote_get_thread_local_address (struct target_ops *ops, /* Provide thread local base, i.e. Thread Information Block address. Returns 1 if ptid is found and thread_local_base is non zero. */ -int +static int remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr) { if (remote_protocol_packets[PACKET_qGetTIBAddr].support != PACKET_DISABLE) @@ -8984,7 +9411,7 @@ static int remote_read_description_p (struct target_ops *target) { struct remote_g_packet_data *data - = gdbarch_data (target_gdbarch, remote_g_packet_data_handle); + = gdbarch_data (target_gdbarch (), remote_g_packet_data_handle); if (!VEC_empty (remote_g_packet_guess_s, data->guesses)) return 1; @@ -8996,7 +9423,7 @@ static const struct target_desc * remote_read_description (struct target_ops *target) { struct remote_g_packet_data *data - = gdbarch_data (target_gdbarch, remote_g_packet_data_handle); + = gdbarch_data (target_gdbarch (), remote_g_packet_data_handle); /* Do not try this during initial connection, when we do not know whether there is a running but stopped thread. */ @@ -9353,6 +9780,44 @@ remote_hostio_unlink (const char *filename, int *remote_errno) remote_errno, NULL, NULL); } +/* Read value of symbolic link FILENAME on the remote target. Return + a null-terminated string allocated via xmalloc, or NULL if an error + occurs (and set *REMOTE_ERRNO). */ + +static char * +remote_hostio_readlink (const char *filename, int *remote_errno) +{ + struct remote_state *rs = get_remote_state (); + char *p = rs->buf; + char *attachment; + int left = get_remote_packet_size (); + int len, attachment_len; + int read_len; + char *ret; + + remote_buffer_add_string (&p, &left, "vFile:readlink:"); + + remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename, + strlen (filename)); + + len = remote_hostio_send_command (p - rs->buf, PACKET_vFile_readlink, + remote_errno, &attachment, + &attachment_len); + + if (len < 0) + return NULL; + + ret = xmalloc (len + 1); + + read_len = remote_unescape_input (attachment, attachment_len, + ret, len); + if (read_len != len) + error (_("Readlink returned %d, but %d bytes."), len, read_len); + + ret[len] = '\0'; + return ret; +} + static int remote_fileio_errno_to_host (int errnum) { @@ -9459,7 +9924,8 @@ remote_bfd_iovec_close (struct bfd *abfd, void *stream) connection was already torn down. */ remote_hostio_close (fd, &remote_errno); - return 1; + /* Zero means success. */ + return 0; } static file_ptr @@ -9508,11 +9974,13 @@ remote_filename_p (const char *filename) bfd * remote_bfd_open (const char *remote_file, const char *target) { - return bfd_openr_iovec (remote_file, target, - remote_bfd_iovec_open, NULL, - remote_bfd_iovec_pread, - remote_bfd_iovec_close, - remote_bfd_iovec_stat); + bfd *abfd = gdb_bfd_openr_iovec (remote_file, target, + remote_bfd_iovec_open, NULL, + remote_bfd_iovec_pread, + remote_bfd_iovec_close, + remote_bfd_iovec_stat); + + return abfd; } void @@ -9767,10 +10235,14 @@ remote_supports_multi_process (void) { struct remote_state *rs = get_remote_state (); - return remote_multi_process_p (rs); + /* Only extended-remote handles being attached to multiple + processes, even though plain remote can use the multi-process + thread id extensions, so that GDB knows the target process's + PID. */ + return rs->extended && remote_multi_process_p (rs); } -int +static int remote_supports_cond_tracepoints (void) { struct remote_state *rs = get_remote_state (); @@ -9778,7 +10250,15 @@ remote_supports_cond_tracepoints (void) return rs->cond_tracepoints; } -int +static int +remote_supports_cond_breakpoints (void) +{ + struct remote_state *rs = get_remote_state (); + + return rs->cond_breakpoints; +} + +static int remote_supports_fast_tracepoints (void) { struct remote_state *rs = get_remote_state (); @@ -9818,6 +10298,14 @@ remote_supports_string_tracing (void) return rs->string_tracing; } +static int +remote_can_run_breakpoint_commands (void) +{ + struct remote_state *rs = get_remote_state (); + + return rs->breakpoint_commands; +} + static void remote_trace_init (void) { @@ -9892,10 +10380,11 @@ remote_download_command_source (int num, ULONGEST addr, static void remote_download_tracepoint (struct bp_location *loc) { +#define BUF_SIZE 2048 CORE_ADDR tpaddr; char addrbuf[40]; - char buf[2048]; + char buf[BUF_SIZE]; char **tdp_actions; char **stepping_actions; int ndx; @@ -9914,10 +10403,10 @@ remote_download_tracepoint (struct bp_location *loc) tpaddr = loc->address; sprintf_vma (addrbuf, tpaddr); - sprintf (buf, "QTDP:%x:%s:%c:%lx:%x", b->number, - addrbuf, /* address */ - (b->enable_state == bp_enabled ? 'E' : 'D'), - t->step_count, t->pass_count); + xsnprintf (buf, BUF_SIZE, "QTDP:%x:%s:%c:%lx:%x", b->number, + addrbuf, /* address */ + (b->enable_state == bp_enabled ? 'E' : 'D'), + t->step_count, t->pass_count); /* Fast tracepoints are mostly handled by the target, but we can tell the target how big of an instruction block should be moved around. */ @@ -9929,9 +10418,10 @@ remote_download_tracepoint (struct bp_location *loc) { int isize; - if (gdbarch_fast_tracepoint_valid_at (target_gdbarch, + if (gdbarch_fast_tracepoint_valid_at (target_gdbarch (), tpaddr, &isize, NULL)) - sprintf (buf + strlen (buf), ":F%x", isize); + xsnprintf (buf + strlen (buf), BUF_SIZE - strlen (buf), ":F%x", + isize); else /* If it passed validation at definition but fails now, something is very wrong. */ @@ -9975,7 +10465,8 @@ remote_download_tracepoint (struct bp_location *loc) { aexpr = gen_eval_for_expr (tpaddr, loc->cond); aexpr_chain = make_cleanup_free_agent_expr (aexpr); - sprintf (buf + strlen (buf), ":X%x,", aexpr->len); + xsnprintf (buf + strlen (buf), BUF_SIZE - strlen (buf), ":X%x,", + aexpr->len); pkt = buf + strlen (buf); for (ndx = 0; ndx < aexpr->len; ++ndx) pkt = pack_hex_byte (pkt, aexpr->buf[ndx]); @@ -10000,11 +10491,11 @@ remote_download_tracepoint (struct bp_location *loc) for (ndx = 0; tdp_actions[ndx]; ndx++) { QUIT; /* Allow user to bail out with ^C. */ - sprintf (buf, "QTDP:-%x:%s:%s%c", - b->number, addrbuf, /* address */ - tdp_actions[ndx], - ((tdp_actions[ndx + 1] || stepping_actions) - ? '-' : 0)); + xsnprintf (buf, BUF_SIZE, "QTDP:-%x:%s:%s%c", + b->number, addrbuf, /* address */ + tdp_actions[ndx], + ((tdp_actions[ndx + 1] || stepping_actions) + ? '-' : 0)); putpkt (buf); remote_get_noisy_reply (&target_buf, &target_buf_size); @@ -10017,11 +10508,11 @@ remote_download_tracepoint (struct bp_location *loc) for (ndx = 0; stepping_actions[ndx]; ndx++) { QUIT; /* Allow user to bail out with ^C. */ - sprintf (buf, "QTDP:-%x:%s:%s%s%s", - b->number, addrbuf, /* address */ - ((ndx == 0) ? "S" : ""), - stepping_actions[ndx], - (stepping_actions[ndx + 1] ? "-" : "")); + xsnprintf (buf, BUF_SIZE, "QTDP:-%x:%s:%s%s%s", + b->number, addrbuf, /* address */ + ((ndx == 0) ? "S" : ""), + stepping_actions[ndx], + (stepping_actions[ndx + 1] ? "-" : "")); putpkt (buf); remote_get_noisy_reply (&target_buf, &target_buf_size); @@ -10097,8 +10588,9 @@ remote_download_trace_state_variable (struct trace_state_variable *tsv) struct remote_state *rs = get_remote_state (); char *p; - sprintf (rs->buf, "QTDV:%x:%s:%x:", - tsv->number, phex ((ULONGEST) tsv->initial_value, 8), tsv->builtin); + xsnprintf (rs->buf, get_remote_packet_size (), "QTDV:%x:%s:%x:", + tsv->number, phex ((ULONGEST) tsv->initial_value, 8), + tsv->builtin); p = rs->buf + strlen (rs->buf); if ((p - rs->buf) + strlen (tsv->name) * 2 >= get_remote_packet_size ()) error (_("Trace state variable name too long for tsv definition packet")); @@ -10119,7 +10611,8 @@ remote_enable_tracepoint (struct bp_location *location) char addr_buf[40]; sprintf_vma (addr_buf, location->address); - sprintf (rs->buf, "QTEnable:%x:%s", location->owner->number, addr_buf); + xsnprintf (rs->buf, get_remote_packet_size (), "QTEnable:%x:%s", + location->owner->number, addr_buf); putpkt (rs->buf); remote_get_noisy_reply (&rs->buf, &rs->buf_size); if (*rs->buf == '\0') @@ -10135,7 +10628,8 @@ remote_disable_tracepoint (struct bp_location *location) char addr_buf[40]; sprintf_vma (addr_buf, location->address); - sprintf (rs->buf, "QTDisable:%x:%s", location->owner->number, addr_buf); + xsnprintf (rs->buf, get_remote_packet_size (), "QTDisable:%x:%s", + location->owner->number, addr_buf); putpkt (rs->buf); remote_get_noisy_reply (&rs->buf, &rs->buf_size); if (*rs->buf == '\0') @@ -10148,6 +10642,7 @@ static void remote_trace_set_readonly_regions (void) { asection *s; + bfd *abfd = NULL; bfd_size_type size; bfd_vma vma; int anysecs = 0; @@ -10157,6 +10652,7 @@ remote_trace_set_readonly_regions (void) return; /* No information to give. */ strcpy (target_buf, "QTro"); + offset = strlen (target_buf); for (s = exec_bfd->sections; s; s = s->next) { char tmp1[40], tmp2[40]; @@ -10168,7 +10664,7 @@ remote_trace_set_readonly_regions (void) continue; anysecs = 1; - vma = bfd_get_section_vma (,s); + vma = bfd_get_section_vma (abfd, s); size = bfd_get_section_size (s); sprintf_vma (tmp1, vma); sprintf_vma (tmp2, vma + size); @@ -10181,7 +10677,8 @@ remote_trace_set_readonly_regions (void) Too many sections for read-only sections definition packet.")); break; } - sprintf (target_buf + offset, ":%s,%s", tmp1, tmp2); + xsnprintf (target_buf + offset, target_buf_size - offset, ":%s,%s", + tmp1, tmp2); offset += sec_length; } if (anysecs) @@ -10221,8 +10718,12 @@ remote_get_trace_status (struct trace_status *ts) } if (ex.reason < 0) { - exception_fprintf (gdb_stderr, ex, "qTStatus: "); - return -1; + if (ex.error != TARGET_CLOSE_ERROR) + { + exception_fprintf (gdb_stderr, ex, "qTStatus: "); + return -1; + } + throw_exception (ex); } /* If the remote target doesn't do tracing, flag it. */ @@ -10230,23 +10731,19 @@ remote_get_trace_status (struct trace_status *ts) return -1; /* We're working with a live target. */ - ts->from_file = 0; - - /* Set some defaults. */ - ts->running_known = 0; - ts->stop_reason = trace_stop_reason_unknown; - ts->traceframe_count = -1; - ts->buffer_free = 0; + ts->filename = NULL; if (*p++ != 'T') error (_("Bogus trace status reply from target: %s"), target_buf); + /* Function 'parse_trace_status' sets default value of each field of + 'ts' at first, so we don't have to do it here. */ parse_trace_status (p, ts); return ts->running; } -void +static void remote_get_tracepoint_status (struct breakpoint *bp, struct uploaded_tp *utp) { @@ -10254,6 +10751,7 @@ remote_get_tracepoint_status (struct breakpoint *bp, char *reply; struct bp_location *loc; struct tracepoint *tp = (struct tracepoint *) bp; + size_t size = get_remote_packet_size (); if (tp) { @@ -10265,8 +10763,8 @@ remote_get_tracepoint_status (struct breakpoint *bp, any status. */ if (tp->number_on_target == 0) continue; - sprintf (rs->buf, "qTP:%x:%s", tp->number_on_target, - phex_nz (loc->address, 0)); + xsnprintf (rs->buf, size, "qTP:%x:%s", tp->number_on_target, + phex_nz (loc->address, 0)); putpkt (rs->buf); reply = remote_get_noisy_reply (&target_buf, &target_buf_size); if (reply && *reply) @@ -10280,7 +10778,8 @@ remote_get_tracepoint_status (struct breakpoint *bp, { utp->hit_count = 0; utp->traceframe_usage = 0; - sprintf (rs->buf, "qTP:%x:%s", utp->number, phex_nz (utp->addr, 0)); + xsnprintf (rs->buf, size, "qTP:%x:%s", utp->number, + phex_nz (utp->addr, 0)); putpkt (rs->buf); reply = remote_get_noisy_reply (&target_buf, &target_buf_size); if (reply && *reply) @@ -10308,6 +10807,7 @@ remote_trace_find (enum trace_find_type type, int num, int *tpp) { struct remote_state *rs = get_remote_state (); + char *endbuf = rs->buf + get_remote_packet_size (); char *p, *reply; int target_frameno = -1, target_tracept = -1; @@ -10323,19 +10823,21 @@ remote_trace_find (enum trace_find_type type, int num, switch (type) { case tfind_number: - sprintf (p, "%x", num); + xsnprintf (p, endbuf - p, "%x", num); break; case tfind_pc: - sprintf (p, "pc:%s", phex_nz (addr1, 0)); + xsnprintf (p, endbuf - p, "pc:%s", phex_nz (addr1, 0)); break; case tfind_tp: - sprintf (p, "tdp:%x", num); + xsnprintf (p, endbuf - p, "tdp:%x", num); break; case tfind_range: - sprintf (p, "range:%s:%s", phex_nz (addr1, 0), phex_nz (addr2, 0)); + xsnprintf (p, endbuf - p, "range:%s:%s", phex_nz (addr1, 0), + phex_nz (addr2, 0)); break; case tfind_outside: - sprintf (p, "outside:%s:%s", phex_nz (addr1, 0), phex_nz (addr2, 0)); + xsnprintf (p, endbuf - p, "outside:%s:%s", phex_nz (addr1, 0), + phex_nz (addr2, 0)); break; default: error (_("Unknown trace find type %d"), type); @@ -10390,7 +10892,7 @@ remote_get_trace_state_variable_value (int tsvnum, LONGEST *val) set_remote_traceframe (); - sprintf (rs->buf, "qTV:%x", tsvnum); + xsnprintf (rs->buf, get_remote_packet_size (), "qTV:%x", tsvnum); putpkt (rs->buf); reply = remote_get_noisy_reply (&target_buf, &target_buf_size); if (reply && *reply) @@ -10479,7 +10981,7 @@ remote_set_disconnected_tracing (int val) { char *reply; - sprintf (rs->buf, "QTDisconnected:%x", val); + xsnprintf (rs->buf, get_remote_packet_size (), "QTDisconnected:%x", val); putpkt (rs->buf); reply = remote_get_noisy_reply (&target_buf, &target_buf_size); if (*reply == '\0') @@ -10507,7 +11009,7 @@ remote_set_circular_trace_buffer (int val) struct remote_state *rs = get_remote_state (); char *reply; - sprintf (rs->buf, "QTBuffer:circular:%x", val); + xsnprintf (rs->buf, get_remote_packet_size (), "QTBuffer:circular:%x", val); putpkt (rs->buf); reply = remote_get_noisy_reply (&target_buf, &target_buf_size); if (*reply == '\0') @@ -10547,7 +11049,15 @@ remote_get_min_fast_tracepoint_insn_len (void) struct remote_state *rs = get_remote_state (); char *reply; - sprintf (rs->buf, "qTMinFTPILen"); + /* If we're not debugging a process yet, the IPA can't be + loaded. */ + if (!target_has_execution) + return 0; + + /* Make sure the remote is pointing at the right process. */ + set_general_process (); + + xsnprintf (rs->buf, get_remote_packet_size (), "qTMinFTPILen"); putpkt (rs->buf); reply = remote_get_noisy_reply (&target_buf, &target_buf_size); if (*reply == '\0') @@ -10562,6 +11072,38 @@ remote_get_min_fast_tracepoint_insn_len (void) } } +static void +remote_set_trace_buffer_size (LONGEST val) +{ + if (remote_protocol_packets[PACKET_QTBuffer_size].support + != PACKET_DISABLE) + { + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + char *endbuf = rs->buf + get_remote_packet_size (); + enum packet_result result; + + gdb_assert (val >= 0 || val == -1); + buf += xsnprintf (buf, endbuf - buf, "QTBuffer:size:"); + /* Send -1 as literal "-1" to avoid host size dependency. */ + if (val < 0) + { + *buf++ = '-'; + buf += hexnumstr (buf, (ULONGEST) -val); + } + else + buf += hexnumstr (buf, (ULONGEST) val); + + putpkt (rs->buf); + remote_get_noisy_reply (&rs->buf, &rs->buf_size); + result = packet_ok (rs->buf, + &remote_protocol_packets[PACKET_QTBuffer_size]); + + if (result != PACKET_OK) + warning (_("Bogus reply from target: %s"), rs->buf); + } +} + static int remote_set_trace_notes (char *user, char *notes, char *stop_notes) { @@ -10607,6 +11149,178 @@ remote_set_trace_notes (char *user, char *notes, char *stop_notes) return 1; } +static int +remote_use_agent (int use) +{ + if (remote_protocol_packets[PACKET_QAgent].support != PACKET_DISABLE) + { + struct remote_state *rs = get_remote_state (); + + /* If the stub supports QAgent. */ + xsnprintf (rs->buf, get_remote_packet_size (), "QAgent:%d", use); + putpkt (rs->buf); + getpkt (&rs->buf, &rs->buf_size, 0); + + if (strcmp (rs->buf, "OK") == 0) + { + use_agent = use; + return 1; + } + } + + return 0; +} + +static int +remote_can_use_agent (void) +{ + return (remote_protocol_packets[PACKET_QAgent].support != PACKET_DISABLE); +} + +struct btrace_target_info +{ + /* The ptid of the traced thread. */ + ptid_t ptid; +}; + +/* Check whether the target supports branch tracing. */ + +static int +remote_supports_btrace (void) +{ + if (remote_protocol_packets[PACKET_Qbtrace_off].support != PACKET_ENABLE) + return 0; + if (remote_protocol_packets[PACKET_Qbtrace_bts].support != PACKET_ENABLE) + return 0; + if (remote_protocol_packets[PACKET_qXfer_btrace].support != PACKET_ENABLE) + return 0; + + return 1; +} + +/* Enable branch tracing. */ + +static struct btrace_target_info * +remote_enable_btrace (ptid_t ptid) +{ + struct btrace_target_info *tinfo = NULL; + struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_bts]; + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + char *endbuf = rs->buf + get_remote_packet_size (); + + if (packet->support != PACKET_ENABLE) + error (_("Target does not support branch tracing.")); + + set_general_thread (ptid); + + buf += xsnprintf (buf, endbuf - buf, "%s", packet->name); + putpkt (rs->buf); + getpkt (&rs->buf, &rs->buf_size, 0); + + if (packet_ok (rs->buf, packet) == PACKET_ERROR) + { + if (rs->buf[0] == 'E' && rs->buf[1] == '.') + error (_("Could not enable branch tracing for %s: %s"), + target_pid_to_str (ptid), rs->buf + 2); + else + error (_("Could not enable branch tracing for %s."), + target_pid_to_str (ptid)); + } + + tinfo = xzalloc (sizeof (*tinfo)); + tinfo->ptid = ptid; + + return tinfo; +} + +/* Disable branch tracing. */ + +static void +remote_disable_btrace (struct btrace_target_info *tinfo) +{ + struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_off]; + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + char *endbuf = rs->buf + get_remote_packet_size (); + + if (packet->support != PACKET_ENABLE) + error (_("Target does not support branch tracing.")); + + set_general_thread (tinfo->ptid); + + buf += xsnprintf (buf, endbuf - buf, "%s", packet->name); + putpkt (rs->buf); + getpkt (&rs->buf, &rs->buf_size, 0); + + if (packet_ok (rs->buf, packet) == PACKET_ERROR) + { + if (rs->buf[0] == 'E' && rs->buf[1] == '.') + error (_("Could not disable branch tracing for %s: %s"), + target_pid_to_str (tinfo->ptid), rs->buf + 2); + else + error (_("Could not disable branch tracing for %s."), + target_pid_to_str (tinfo->ptid)); + } + + xfree (tinfo); +} + +/* Teardown branch tracing. */ + +static void +remote_teardown_btrace (struct btrace_target_info *tinfo) +{ + /* We must not talk to the target during teardown. */ + xfree (tinfo); +} + +/* Read the branch trace. */ + +static VEC (btrace_block_s) * +remote_read_btrace (struct btrace_target_info *tinfo, + enum btrace_read_type type) +{ + struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace]; + struct remote_state *rs = get_remote_state (); + VEC (btrace_block_s) *btrace = NULL; + const char *annex; + char *xml; + + if (packet->support != PACKET_ENABLE) + error (_("Target does not support branch tracing.")); + +#if !defined(HAVE_LIBEXPAT) + error (_("Cannot process branch tracing result. XML parsing not supported.")); +#endif + + switch (type) + { + case btrace_read_all: + annex = "all"; + break; + case btrace_read_new: + annex = "new"; + break; + default: + internal_error (__FILE__, __LINE__, + _("Bad branch tracing read type: %u."), + (unsigned int) type); + } + + xml = target_read_stralloc (¤t_target, + TARGET_OBJECT_BTRACE, annex); + if (xml != NULL) + { + struct cleanup *cleanup = make_cleanup (xfree, xml); + + btrace = parse_xml_btrace (xml); + do_cleanups (cleanup); + } + + return btrace; +} + static void init_remote_ops (void) { @@ -10631,6 +11345,8 @@ Specify the serial device it is connected to\n\ remote_ops.to_remove_breakpoint = remote_remove_breakpoint; remote_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint; remote_ops.to_stopped_data_address = remote_stopped_data_address; + remote_ops.to_watchpoint_addr_within_range = + remote_watchpoint_addr_within_range; remote_ops.to_can_use_hw_breakpoint = remote_check_watch_resources; remote_ops.to_insert_hw_breakpoint = remote_insert_hw_breakpoint; remote_ops.to_remove_hw_breakpoint = remote_remove_hw_breakpoint; @@ -10642,6 +11358,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_load = generic_load; remote_ops.to_mourn_inferior = remote_mourn; remote_ops.to_pass_signals = remote_pass_signals; + remote_ops.to_program_signals = remote_program_signals; remote_ops.to_thread_alive = remote_thread_alive; remote_ops.to_find_new_threads = remote_threads_info; remote_ops.to_pid_to_str = remote_pid_to_str; @@ -10675,8 +11392,16 @@ Specify the serial device it is connected to\n\ remote_ops.to_supports_multi_process = remote_supports_multi_process; remote_ops.to_supports_disable_randomization = remote_supports_disable_randomization; + remote_ops.to_fileio_open = remote_hostio_open; + remote_ops.to_fileio_pwrite = remote_hostio_pwrite; + remote_ops.to_fileio_pread = remote_hostio_pread; + remote_ops.to_fileio_close = remote_hostio_close; + remote_ops.to_fileio_unlink = remote_hostio_unlink; + remote_ops.to_fileio_readlink = remote_hostio_readlink; remote_ops.to_supports_enable_disable_tracepoint = remote_supports_enable_disable_tracepoint; remote_ops.to_supports_string_tracing = remote_supports_string_tracing; + remote_ops.to_supports_evaluation_of_breakpoint_conditions = remote_supports_cond_breakpoints; + remote_ops.to_can_run_breakpoint_commands = remote_can_run_breakpoint_commands; remote_ops.to_trace_init = remote_trace_init; remote_ops.to_download_tracepoint = remote_download_tracepoint; remote_ops.to_can_download_tracepoint = remote_can_download_tracepoint; @@ -10700,6 +11425,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_get_min_fast_tracepoint_insn_len = remote_get_min_fast_tracepoint_insn_len; remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing; remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer; + remote_ops.to_set_trace_buffer_size = remote_set_trace_buffer_size; remote_ops.to_set_trace_notes = remote_set_trace_notes; remote_ops.to_core_of_thread = remote_core_of_thread; remote_ops.to_verify_memory = remote_verify_memory; @@ -10710,6 +11436,13 @@ Specify the serial device it is connected to\n\ remote_ops.to_static_tracepoint_markers_by_strid = remote_static_tracepoint_markers_by_strid; remote_ops.to_traceframe_info = remote_traceframe_info; + remote_ops.to_use_agent = remote_use_agent; + remote_ops.to_can_use_agent = remote_can_use_agent; + remote_ops.to_supports_btrace = remote_supports_btrace; + remote_ops.to_enable_btrace = remote_enable_btrace; + remote_ops.to_disable_btrace = remote_disable_btrace; + remote_ops.to_teardown_btrace = remote_teardown_btrace; + remote_ops.to_read_btrace = remote_read_btrace; } /* Set up the extended remote vector by making a copy of the standard @@ -10781,12 +11514,6 @@ remote_async_inferior_event_handler (gdb_client_data data) inferior_event_handler (INF_REG_EVENT, NULL); } -static void -remote_async_get_pending_events_handler (gdb_client_data data) -{ - remote_get_pending_stop_replies (); -} - static void remote_async (void (*callback) (enum inferior_event_type event_type, void *context), void *context) @@ -10832,7 +11559,7 @@ show_remote_cmd (char *args, int from_tty) ui_out_field_string (uiout, "name", list->name); ui_out_text (uiout, ": "); if (list->type == show_cmd) - do_setshow_command ((char *) NULL, from_tty, list); + do_show_command ((char *) NULL, from_tty, list); else cmd_func (list, NULL, from_tty); /* Close the tuple. */ @@ -10928,6 +11655,9 @@ _initialize_remote (void) /* Hook into new objfile notification. */ observer_attach_new_objfile (remote_new_objfile); + /* We're no longer interested in notification events of an inferior + when it exits. */ + observer_attach_inferior_exit (discard_pending_stop_replies); /* Set up signal handlers. */ sigint_remote_token = @@ -10939,6 +11669,7 @@ _initialize_remote (void) init_remote_threadtests (); #endif + stop_reply_queue = QUEUE_alloc (stop_reply_p, stop_reply_xfree); /* set/show remote ... */ add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, _("\ @@ -11060,13 +11791,13 @@ Specify a negative limit for unlimited."), breakpoints is %s. */ &remote_set_cmdlist, &remote_show_cmdlist); - add_setshow_integer_cmd ("remoteaddresssize", class_obscure, - &remote_address_size, _("\ + add_setshow_uinteger_cmd ("remoteaddresssize", class_obscure, + &remote_address_size, _("\ Set the maximum size of the address (in bits) in a memory packet."), _("\ Show the maximum size of the address (in bits) in a memory packet."), NULL, - NULL, - NULL, /* FIXME: i18n: */ - &setlist, &showlist); + NULL, + NULL, /* FIXME: i18n: */ + &setlist, &showlist); add_packet_config_cmd (&remote_protocol_packets[PACKET_X], "X", "binary-download", 1); @@ -11077,6 +11808,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], "QPassSignals", "pass-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals], + "QProgramSignals", "program-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qSymbol], "qSymbol", "symbol-lookup", 0); @@ -11138,6 +11872,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, (&remote_protocol_packets[PACKET_qXfer_traceframe_info], "qXfer:trace-frame-info:read", "traceframe-info", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_uib], + "qXfer:uib:read", "unwind-info-block", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr], "qGetTLSAddr", "get-thread-local-storage-address", 0); @@ -11173,6 +11910,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_unlink], "vFile:unlink", "hostio-unlink", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_readlink], + "vFile:readlink", "hostio-readlink", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_vAttach], "vAttach", "attach", 0); @@ -11191,6 +11931,15 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_ConditionalTracepoints], "ConditionalTracepoints", "conditional-tracepoints", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_ConditionalBreakpoints], + "ConditionalBreakpoints", + "conditional-breakpoints", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_BreakpointCommands], + "BreakpointCommands", + "breakpoint-commands", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_FastTracepoints], "FastTracepoints", "fast-tracepoints", 0); @@ -11215,6 +11964,21 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_QDisableRandomization], "QDisableRandomization", "disable-randomization", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QAgent], + "QAgent", "agent", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_QTBuffer_size], + "QTBuffer:size", "trace-buffer-size", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_off], + "Qbtrace:off", "disable-btrace", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_bts], + "Qbtrace:bts", "enable-btrace", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace], + "qXfer:btrace", "read-btrace", 0); + /* Keep the old ``set remote Z-packet ...'' working. Each individual Z sub-packet has its own set and show commands, but users may have sets to this variable in their .gdbinit files (or in their diff --git a/contrib/gdb-7/gdb/remote.h b/contrib/gdb-7/gdb/remote.h index 3adc54ee6c..b95370c21f 100644 --- a/contrib/gdb-7/gdb/remote.h +++ b/contrib/gdb-7/gdb/remote.h @@ -1,5 +1,5 @@ /* Remote target communications for serial-line targets in custom GDB protocol - Copyright (C) 1999, 2003-2012 Free Software Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -19,6 +19,8 @@ #ifndef REMOTE_H #define REMOTE_H +#include "remote-notif.h" + struct target_desc; /* Read a packet from the remote machine, with error checking, and @@ -37,6 +39,10 @@ extern void getpkt (char **buf, long *sizeof_buf, int forever); extern int putpkt (char *buf); +extern int hex2bin (const char *hex, gdb_byte *bin, int count); + +extern int bin2hex (const gdb_byte *bin, char *hex, int count); + extern char *unpack_varlen_hex (char *buff, ULONGEST *result); extern void async_remote_interrupt_twice (void *arg); @@ -59,4 +65,5 @@ extern int remote_register_number_and_offset (struct gdbarch *gdbarch, int regnum, int *pnum, int *poffset); +extern void remote_notif_get_pending_events (struct notif_client *np); #endif diff --git a/contrib/gdb-7/gdb/reverse.c b/contrib/gdb-7/gdb/reverse.c index 042296ee25..171c53c230 100644 --- a/contrib/gdb-7/gdb/reverse.c +++ b/contrib/gdb-7/gdb/reverse.c @@ -1,6 +1,6 @@ /* Reverse execution and reverse debugging. - Copyright (C) 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2006-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -216,7 +216,6 @@ delete_all_bookmarks (void) static void delete_bookmark_command (char *args, int from_tty) { - struct bookmark *b; int num; struct get_number_or_range_state state; diff --git a/contrib/gdb-7/gdb/sentinel-frame.c b/contrib/gdb-7/gdb/sentinel-frame.c index 9d1a81e9fa..26fe24527d 100644 --- a/contrib/gdb-7/gdb/sentinel-frame.c +++ b/contrib/gdb-7/gdb/sentinel-frame.c @@ -1,6 +1,6 @@ /* Code dealing with register stack frames, for GDB, the GNU debugger. - Copyright (C) 1986-2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/sentinel-frame.h b/contrib/gdb-7/gdb/sentinel-frame.h index 7bb1e87064..3bef12e913 100644 --- a/contrib/gdb-7/gdb/sentinel-frame.h +++ b/contrib/gdb-7/gdb/sentinel-frame.h @@ -1,6 +1,6 @@ /* Code dealing with register stack frames, for GDB, the GNU debugger. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/ser-base.c b/contrib/gdb-7/gdb/ser-base.c index b4399d0c4b..c602650b2e 100644 --- a/contrib/gdb-7/gdb/ser-base.c +++ b/contrib/gdb-7/gdb/ser-base.c @@ -1,7 +1,6 @@ /* Generic serial interface functions. - Copyright (C) 1992-1996, 1998-2001, 2003-2012 Free Software - Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -25,6 +24,7 @@ #include "gdb_select.h" #include "gdb_string.h" +#include "gdb_assert.h" #include #ifdef USE_WIN32API #include @@ -123,6 +123,29 @@ reschedule (struct serial *scb) } } +/* Run the SCB's async handle, and reschedule, if the handler doesn't + close SCB. */ + +static void +run_async_handler_and_reschedule (struct serial *scb) +{ + int is_open; + + /* Take a reference, so a serial_close call within the handler + doesn't make SCB a dangling pointer. */ + serial_ref (scb); + + /* Run the handler. */ + scb->async_handler (scb, scb->async_context); + + is_open = serial_is_open (scb); + serial_unref (scb); + + /* Get ready for more, if not already closed. */ + if (is_open) + reschedule (scb); +} + /* FD_EVENT: This is scheduled when the input FIFO is empty (and there is no pending error). As soon as data arrives, it is read into the input FIFO and the client notified. The client should then drain @@ -158,8 +181,7 @@ fd_event (int error, void *context) scb->bufcnt = SERIAL_ERROR; } } - scb->async_handler (scb, scb->async_context); - reschedule (scb); + run_async_handler_and_reschedule (scb); } /* PUSH_EVENT: The input FIFO is non-empty (or there is a pending @@ -173,9 +195,7 @@ push_event (void *context) struct serial *scb = context; scb->async_state = NOTHING_SCHEDULED; /* Timers are one-off */ - scb->async_handler (scb, scb->async_context); - /* re-schedule */ - reschedule (scb); + run_async_handler_and_reschedule (scb); } /* Wait for input on scb, with timeout seconds. Returns 0 on success, @@ -222,6 +242,64 @@ ser_base_wait_for (struct serial *scb, int timeout) } } +/* Read any error output we might have. */ + +static void +ser_base_read_error_fd (struct serial *scb, int close_fd) +{ + if (scb->error_fd != -1) + { + ssize_t s; + char buf[GDB_MI_MSG_WIDTH + 1]; + + for (;;) + { + char *current; + char *newline; + int to_read = GDB_MI_MSG_WIDTH; + int num_bytes = -1; + + if (scb->ops->avail) + num_bytes = (scb->ops->avail)(scb, scb->error_fd); + + if (num_bytes != -1) + to_read = (num_bytes < to_read) ? num_bytes : to_read; + + if (to_read == 0) + break; + + s = read (scb->error_fd, &buf, to_read); + if ((s == -1) || (s == 0 && !close_fd)) + break; + + if (s == 0 && close_fd) + { + /* End of file. */ + close (scb->error_fd); + scb->error_fd = -1; + break; + } + + /* In theory, embedded newlines are not a problem. + But for MI, we want each output line to have just + one newline for legibility. So output things + in newline chunks. */ + gdb_assert (s > 0 && s <= GDB_MI_MSG_WIDTH); + buf[s] = '\0'; + current = buf; + while ((newline = strstr (current, "\n")) != NULL) + { + *newline = '\0'; + fputs_unfiltered (current, gdb_stderr); + fputs_unfiltered ("\n", gdb_stderr); + current = newline + 1; + } + + fputs_unfiltered (current, gdb_stderr); + } + } +} + /* Read a character with user-specified timeout. TIMEOUT is number of seconds to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns char if successful. Returns -2 if timeout expired, EOF if line dropped @@ -272,6 +350,11 @@ do_ser_base_readchar (struct serial *scb, int timeout) status = SERIAL_TIMEOUT; break; } + + /* We also need to check and consume the stderr because it could + come before the stdout for some stubs. If we just sit and wait + for stdout, we would hit a deadlock for that case. */ + ser_base_read_error_fd (scb, 0); } if (status < 0) @@ -342,54 +425,9 @@ generic_readchar (struct serial *scb, int timeout, } } } - /* Read any error output we might have. */ - if (scb->error_fd != -1) - { - ssize_t s; - char buf[81]; - - for (;;) - { - char *current; - char *newline; - int to_read = 80; - - int num_bytes = -1; - if (scb->ops->avail) - num_bytes = (scb->ops->avail)(scb, scb->error_fd); - if (num_bytes != -1) - to_read = (num_bytes < to_read) ? num_bytes : to_read; - - if (to_read == 0) - break; - s = read (scb->error_fd, &buf, to_read); - if (s == -1) - break; - if (s == 0) - { - /* EOF */ - close (scb->error_fd); - scb->error_fd = -1; - break; - } - - /* In theory, embedded newlines are not a problem. - But for MI, we want each output line to have just - one newline for legibility. So output things - in newline chunks. */ - buf[s] = '\0'; - current = buf; - while ((newline = strstr (current, "\n")) != NULL) - { - *newline = '\0'; - fputs_unfiltered (current, gdb_stderr); - fputs_unfiltered ("\n", gdb_stderr); - current = newline + 1; - } - fputs_unfiltered (current, gdb_stderr); - } - } + /* Read any error output we might have. */ + ser_base_read_error_fd (scb, 1); reschedule (scb); return ch; diff --git a/contrib/gdb-7/gdb/ser-base.h b/contrib/gdb-7/gdb/ser-base.h index ba6849aa8d..175bf20904 100644 --- a/contrib/gdb-7/gdb/ser-base.h +++ b/contrib/gdb-7/gdb/ser-base.h @@ -1,6 +1,6 @@ /* Generic serial interface functions. - Copyright (C) 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/ser-pipe.c b/contrib/gdb-7/gdb/ser-pipe.c index 4616a7e9ab..9a98923895 100644 --- a/contrib/gdb-7/gdb/ser-pipe.c +++ b/contrib/gdb-7/gdb/ser-pipe.c @@ -1,5 +1,5 @@ /* Serial interface for a pipe to a separate program - Copyright (C) 1999-2001, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. Contributed by Cygnus Solutions. @@ -30,7 +30,6 @@ #include #include #include "gdb_string.h" -#include "gdb_wait.h" #include @@ -162,14 +161,30 @@ pipe_close (struct serial *scb) if (state != NULL) { - int status; - kill (state->pid, SIGTERM); -#ifdef HAVE_WAITPID + int wait_result, status; + + /* Don't kill the task right away, give it a chance to shut down cleanly. + But don't wait forever though. */ +#define PIPE_CLOSE_TIMEOUT 5 + /* Assume the program will exit after SIGTERM. Might be useful to print any remaining stderr output from scb->error_fd while waiting. */ - waitpid (state->pid, &status, 0); +#define SIGTERM_TIMEOUT INT_MAX + + wait_result = -1; +#ifdef HAVE_WAITPID + wait_result = wait_to_die_with_timeout (state->pid, &status, + PIPE_CLOSE_TIMEOUT); #endif + if (wait_result == -1) + { + kill (state->pid, SIGTERM); +#ifdef HAVE_WAITPID + wait_to_die_with_timeout (state->pid, &status, SIGTERM_TIMEOUT); +#endif + } + if (scb->error_fd != -1) close (scb->error_fd); scb->error_fd = -1; diff --git a/contrib/gdb-7/gdb/ser-tcp.c b/contrib/gdb-7/gdb/ser-tcp.c index d96a8e5f46..34c6af1f31 100644 --- a/contrib/gdb-7/gdb/ser-tcp.c +++ b/contrib/gdb-7/gdb/ser-tcp.c @@ -1,7 +1,6 @@ /* Serial interface for raw TCP connections on Un*x like systems. - Copyright (C) 1992-1996, 1998-1999, 2001, 2005-2012 Free Software - Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -73,7 +72,7 @@ static int tcp_auto_retry = 1; /* Timeout period for connections, in seconds. */ -static int tcp_retry_limit = 15; +static unsigned int tcp_retry_limit = 15; /* How many times per second to poll deprecated_ui_loop_hook. */ diff --git a/contrib/gdb-7/gdb/ser-tcp.h b/contrib/gdb-7/gdb/ser-tcp.h index 45881f6f80..df69a7556f 100644 --- a/contrib/gdb-7/gdb/ser-tcp.h +++ b/contrib/gdb-7/gdb/ser-tcp.h @@ -1,6 +1,6 @@ /* Serial interface for raw TCP connections on Un*x like systems. - Copyright (C) 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2006-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/ser-unix.c b/contrib/gdb-7/gdb/ser-unix.c index 4aab7cab0f..9ec8bb1099 100644 --- a/contrib/gdb-7/gdb/ser-unix.c +++ b/contrib/gdb-7/gdb/ser-unix.c @@ -1,7 +1,6 @@ /* Serial interface for local (hardwired) serial ports on Un*x like systems - Copyright (C) 1992-1996, 1998-2001, 2003-2005, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/ser-unix.h b/contrib/gdb-7/gdb/ser-unix.h index 4037733c23..fe428ccd1a 100644 --- a/contrib/gdb-7/gdb/ser-unix.h +++ b/contrib/gdb-7/gdb/ser-unix.h @@ -1,7 +1,6 @@ /* Serial interface for UN*X file-descriptor based connection. - Copyright (C) 1999-2000, 2002, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/serial.c b/contrib/gdb-7/gdb/serial.c index 868858a8e2..3202b0f6ba 100644 --- a/contrib/gdb-7/gdb/serial.c +++ b/contrib/gdb-7/gdb/serial.c @@ -1,6 +1,6 @@ /* Generic serial interface routines - Copyright (C) 1992-2002, 2004-2012 Free Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,21 +22,18 @@ #include "serial.h" #include "gdb_string.h" #include "gdbcmd.h" +#include "cli/cli-utils.h" extern void _initialize_serial (void); /* Is serial being debugged? */ -static int global_serial_debug_p; +static unsigned int global_serial_debug_p; /* Linked list of serial I/O handlers. */ static struct serial_ops *serial_ops_list = NULL; -/* This is the last serial stream opened. Used by connect command. */ - -static struct serial *last_serial_opened = NULL; - /* Pointer to list of scb's. */ static struct serial *scb_base; @@ -53,7 +50,7 @@ static void serial_logchar (struct ui_file *stream, static const char logbase_hex[] = "hex"; static const char logbase_octal[] = "octal"; static const char logbase_ascii[] = "ascii"; -static const char *logbase_enums[] = +static const char *const logbase_enums[] = {logbase_hex, logbase_octal, logbase_ascii, NULL}; static const char *serial_logbase = logbase_ascii; @@ -165,6 +162,21 @@ serial_add_interface (struct serial_ops *optable) serial_ops_list = optable; } +/* Return the open serial device for FD, if found, or NULL if FD is + not already opened. */ + +struct serial * +serial_for_fd (int fd) +{ + struct serial *scb; + + for (scb = scb_base; scb; scb = scb->next) + if (scb->fd == fd) + return scb; + + return NULL; +} + /* Open up a device or a network socket, depending upon the syntax of NAME. */ struct serial * @@ -174,13 +186,6 @@ serial_open (const char *name) struct serial_ops *ops; const char *open_name = name; - for (scb = scb_base; scb; scb = scb->next) - if (scb->name && strcmp (scb->name, name) == 0) - { - scb->refcnt++; - return scb; - } - if (strcmp (name, "pc") == 0) ops = serial_interface_lookup ("pc"); else if (strncmp (name, "lpt", 3) == 0) @@ -190,8 +195,7 @@ serial_open (const char *name) ops = serial_interface_lookup ("pipe"); /* Discard ``|'' and any space before the command itself. */ ++open_name; - while (isspace (*open_name)) - ++open_name; + open_name = skip_spaces_const (open_name); } /* Check for a colon, suggesting an IP address/port pair. Do this *after* checking for all the interesting prefixes. We @@ -211,6 +215,7 @@ serial_open (const char *name) scb->bufcnt = 0; scb->bufp = scb->buf; scb->error_fd = -1; + scb->refcnt = 1; /* `...->open (...)' would get expanded by the open(2) syscall macro. */ if ((*scb->ops->open) (scb, open_name)) @@ -221,15 +226,12 @@ serial_open (const char *name) scb->name = xstrdup (name); scb->next = scb_base; - scb->refcnt = 1; scb->debug_p = 0; scb->async_state = 0; scb->async_handler = NULL; scb->async_context = NULL; scb_base = scb; - last_serial_opened = scb; - if (serial_logfile != NULL) { serial_logfp = gdb_fopen (serial_logfile, "w"); @@ -240,21 +242,6 @@ serial_open (const char *name) return scb; } -/* Return the open serial device for FD, if found, or NULL if FD - is not already opened. */ - -struct serial * -serial_for_fd (int fd) -{ - struct serial *scb; - - for (scb = scb_base; scb; scb = scb->next) - if (scb->fd == fd) - return scb; - - return NULL; -} - /* Open a new serial stream using a file handle, using serial interface ops OPS. */ @@ -263,13 +250,6 @@ serial_fdopen_ops (const int fd, struct serial_ops *ops) { struct serial *scb; - scb = serial_for_fd (fd); - if (scb) - { - scb->refcnt++; - return scb; - } - if (!ops) { ops = serial_interface_lookup ("terminal"); @@ -287,10 +267,10 @@ serial_fdopen_ops (const int fd, struct serial_ops *ops) scb->bufcnt = 0; scb->bufp = scb->buf; scb->error_fd = -1; + scb->refcnt = 1; scb->name = NULL; scb->next = scb_base; - scb->refcnt = 1; scb->debug_p = 0; scb->async_state = 0; scb->async_handler = NULL; @@ -302,8 +282,6 @@ serial_fdopen_ops (const int fd, struct serial_ops *ops) else scb->fd = fd; - last_serial_opened = scb; - return scb; } @@ -318,8 +296,6 @@ do_serial_close (struct serial *scb, int really_close) { struct serial *tmp_scb; - last_serial_opened = NULL; - if (serial_logfp) { fputs_unfiltered ("\nEnd of log\n", serial_logfp); @@ -330,16 +306,6 @@ do_serial_close (struct serial *scb, int really_close) serial_logfp = NULL; } -/* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you - should fix your code instead. */ - - if (!scb) - return; - - scb->refcnt--; - if (scb->refcnt > 0) - return; - /* ensure that the FD has been taken out of async mode. */ if (scb->async_handler != NULL) serial_async (scb, NULL, NULL); @@ -350,6 +316,9 @@ do_serial_close (struct serial *scb, int really_close) if (scb->name) xfree (scb->name); + /* For serial_is_open. */ + scb->bufp = NULL; + if (scb_base == scb) scb_base = scb_base->next; else @@ -362,7 +331,7 @@ do_serial_close (struct serial *scb, int really_close) break; } - xfree (scb); + serial_unref (scb); } void @@ -377,6 +346,26 @@ serial_un_fdopen (struct serial *scb) do_serial_close (scb, 0); } +int +serial_is_open (struct serial *scb) +{ + return scb->bufp != NULL; +} + +void +serial_ref (struct serial *scb) +{ + scb->refcnt++; +} + +void +serial_unref (struct serial *scb) +{ + --scb->refcnt; + if (scb->refcnt == 0) + xfree (scb); +} + int serial_readchar (struct serial *scb, int timeout) { @@ -557,19 +546,6 @@ serial_async (struct serial *scb, scb->ops->async (scb, handler != NULL); } -int -deprecated_serial_fd (struct serial *scb) -{ - /* FIXME: should this output a warning that deprecated code is being - called? */ - if (scb->fd < 0) - { - internal_error (__FILE__, __LINE__, - _("serial: FD not valid")); - } - return scb->fd; /* sigh */ -} - void serial_debug (struct serial *scb, int debug_p) { @@ -624,129 +600,6 @@ serial_pipe (struct serial *scbs[2]) return 0; } -#if 0 -/* The connect command is #if 0 because I hadn't thought of an elegant - way to wait for I/O on two `struct serial *'s simultaneously. Two - solutions came to mind: - - 1) Fork, and have have one fork handle the to user direction, - and have the other hand the to target direction. This - obviously won't cut it for MSDOS. - - 2) Use something like select. This assumes that stdin and - the target side can both be waited on via the same - mechanism. This may not be true for DOS, if GDB is - talking to the target via a TCP socket. - -grossman, 8 Jun 93 */ - -/* Connect the user directly to the remote system. This command acts just like - the 'cu' or 'tip' command. Use ~. or ~^D to break out. */ - -static struct serial *tty_desc; /* Controlling terminal */ - -static void -cleanup_tty (serial_ttystate ttystate) -{ - printf_unfiltered ("\r\n[Exiting connect mode]\r\n"); - serial_set_tty_state (tty_desc, ttystate); - xfree (ttystate); - serial_close (tty_desc); -} - -static void -connect_command (char *args, int fromtty) -{ - int c; - char cur_esc = 0; - serial_ttystate ttystate; - struct serial *port_desc; /* TTY port */ - - dont_repeat (); - - if (args) - fprintf_unfiltered (gdb_stderr, - "This command takes no args. " - "They have been ignored.\n"); - - printf_unfiltered ("[Entering connect mode. Use ~. or ~^D to escape]\n"); - - tty_desc = serial_fdopen (0); - port_desc = last_serial_opened; - - ttystate = serial_get_tty_state (tty_desc); - - serial_raw (tty_desc); - serial_raw (port_desc); - - make_cleanup (cleanup_tty, ttystate); - - while (1) - { - int mask; - - mask = serial_wait_2 (tty_desc, port_desc, -1); - - if (mask & 2) - { /* tty input */ - char cx; - - while (1) - { - c = serial_readchar (tty_desc, 0); - - if (c == SERIAL_TIMEOUT) - break; - - if (c < 0) - perror_with_name (_("connect")); - - cx = c; - serial_write (port_desc, &cx, 1); - - switch (cur_esc) - { - case 0: - if (c == '\r') - cur_esc = c; - break; - case '\r': - if (c == '~') - cur_esc = c; - else - cur_esc = 0; - break; - case '~': - if (c == '.' || c == '\004') - return; - else - cur_esc = 0; - } - } - } - - if (mask & 1) - { /* Port input */ - char cx; - - while (1) - { - c = serial_readchar (port_desc, 0); - - if (c == SERIAL_TIMEOUT) - break; - - if (c < 0) - perror_with_name (_("connect")); - - cx = c; - - serial_write (tty_desc, &cx, 1); - } - } - } -} -#endif /* 0 */ - /* Serial set/show framework. */ static struct cmd_list_element *serial_set_cmdlist; @@ -805,12 +658,12 @@ Show numerical base for remote session logging"), NULL, NULL, /* FIXME: i18n: */ &setlist, &showlist); - add_setshow_zinteger_cmd ("serial", class_maintenance, - &global_serial_debug_p, _("\ + add_setshow_zuinteger_cmd ("serial", class_maintenance, + &global_serial_debug_p, _("\ Set serial debugging."), _("\ Show serial debugging."), _("\ When non-zero, serial port debugging is enabled."), - NULL, - NULL, /* FIXME: i18n: */ - &setdebuglist, &showdebuglist); + NULL, + NULL, /* FIXME: i18n: */ + &setdebuglist, &showdebuglist); } diff --git a/contrib/gdb-7/gdb/serial.h b/contrib/gdb-7/gdb/serial.h index 02a3b2d473..a91c8b812a 100644 --- a/contrib/gdb-7/gdb/serial.h +++ b/contrib/gdb-7/gdb/serial.h @@ -1,6 +1,5 @@ /* Remote serial support interface definitions for GDB, the GNU Debugger. - Copyright (C) 1992-1996, 1998-2001, 2004-2012 Free Software - Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -37,13 +36,18 @@ typedef void *serial_ttystate; struct serial; /* Try to open NAME. Returns a new `struct serial *' on success, NULL - on failure. Note that some open calls can block and, if possible, - should be written to be non-blocking, with calls to ui_look_hook - so they can be cancelled. An async interface for open could be - added to GDB if necessary. */ + on failure. The new serial object has a reference count of 1. + Note that some open calls can block and, if possible, should be + written to be non-blocking, with calls to ui_look_hook so they can + be cancelled. An async interface for open could be added to GDB if + necessary. */ extern struct serial *serial_open (const char *name); +/* Returns true if SCB is open. */ + +extern int serial_is_open (struct serial *scb); + /* Find an already opened serial stream using a file handle. */ extern struct serial *serial_for_fd (int fd); @@ -52,10 +56,18 @@ extern struct serial *serial_for_fd (int fd); extern struct serial *serial_fdopen (const int fd); -/* Push out all buffers, close the device and destroy SCB. */ +/* Push out all buffers, close the device and unref SCB. */ extern void serial_close (struct serial *scb); +/* Increment reference count of SCB. */ + +extern void serial_ref (struct serial *scb); + +/* Decrement reference count of SCB. */ + +extern void serial_unref (struct serial *scb); + /* Create a pipe, and put the read end in files[0], and the write end in filde[1]. Returns 0 for success, negative value for error (in which case errno contains the error). */ @@ -192,13 +204,6 @@ typedef void (serial_event_ftype) (struct serial *scb, void *context); extern void serial_async (struct serial *scb, serial_event_ftype *handler, void *context); -/* Provide direct access to the underlying FD (if any) used to - implement the serial device. This interface is clearly - deprecated. Will call internal_error() if the operation isn't - applicable to the current serial device. */ - -extern int deprecated_serial_fd (struct serial *scb); - /* Trace/debug mechanism. serial_debug() enables/disables internal debugging. @@ -213,6 +218,10 @@ extern int serial_debug_p (struct serial *scb); struct serial { + /* serial objects are ref counted (but not the underlying + connection, just the object's lifetime in memory). */ + int refcnt; + int fd; /* File descriptor */ /* File descriptor for a separate error stream that should be immediately forwarded to gdb_stderr. This may be -1. @@ -233,7 +242,6 @@ struct serial more seconds. */ char *name; /* The name of the device or host */ struct serial *next; /* Pointer to the next `struct serial *' */ - int refcnt; /* Number of pointers to this block */ int debug_p; /* Trace this serial devices operation. */ int async_state; /* Async internal state. */ void *async_context; /* Async event thread's context */ diff --git a/contrib/gdb-7/gdb/sim-regno.h b/contrib/gdb-7/gdb/sim-regno.h index 506f7022a1..0feb65304e 100644 --- a/contrib/gdb-7/gdb/sim-regno.h +++ b/contrib/gdb-7/gdb/sim-regno.h @@ -1,6 +1,6 @@ /* Generic remote debugging interface for simulators. - Copyright (C) 2002, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. Contributed by Red Hat, Inc. diff --git a/contrib/gdb-7/gdb/skip.c b/contrib/gdb-7/gdb/skip.c index 637f4e0c50..0c002ff568 100644 --- a/contrib/gdb-7/gdb/skip.c +++ b/contrib/gdb-7/gdb/skip.c @@ -1,6 +1,6 @@ /* Skipping uninteresting files and functions while stepping. - Copyright (C) 2011-2012 Free Software Foundation, Inc. + Copyright (C) 2011-2013 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 @@ -32,6 +32,8 @@ #include "objfiles.h" #include "exceptions.h" #include "breakpoint.h" /* for get_sal_arch () */ +#include "source.h" +#include "filenames.h" struct skiplist_entry { @@ -42,34 +44,17 @@ struct skiplist_entry char *filename; /* The name of the marked-for-skip function, if this is a skiplist - entry for a function. Note that this might be non-null even if - the pc is 0 if the entry is pending a shared library load. - + entry for a function. The skiplist entry owns this pointer. */ char *function_name; - /* 0 if this is a skiplist entry for an entire file, or if this - entry will be on a function, pending a shared library load. */ - CORE_ADDR pc; - - /* Architecture we used to create the skiplist entry. May be null - if the entry is pending a shared library load. */ - struct gdbarch *gdbarch; - int enabled; - int pending; struct skiplist_entry *next; }; -static void skip_function_command (char *arg, int from_tty); -static void skip_file_command (char *arg, int from_tty); -static void skip_info (char *arg, int from_tty); - static void add_skiplist_entry (struct skiplist_entry *e); -static void skip_function_pc (CORE_ADDR pc, char *name, - struct gdbarch *arch, - int pending); +static void skip_function (const char *name); static struct skiplist_entry *skiplist_entry_chain; static int skiplist_entry_count; @@ -87,42 +72,38 @@ skip_file_command (char *arg, int from_tty) { struct skiplist_entry *e; struct symtab *symtab; - int pending = 0; - char *filename = 0; + const char *filename = NULL; /* If no argument was given, try to default to the last displayed codepoint. */ - if (arg == 0) + if (arg == NULL) { symtab = get_last_displayed_symtab (); - if (symtab == 0) + if (symtab == NULL) error (_("No default file now.")); - else - filename = symtab->filename; + + /* It is not a typo, symtab_to_filename_for_display woule be needlessly + ambiguous. */ + filename = symtab_to_fullname (symtab); } else { symtab = lookup_symtab (arg); - if (symtab == 0) + if (symtab == NULL) { fprintf_filtered (gdb_stderr, _("No source file named %s.\n"), arg); if (!nquery (_("\ Ignore file pending future shared library load? "))) return; - - pending = 1; - filename = arg; } - else - filename = symtab->filename; + /* Do not use SYMTAB's filename, later loaded shared libraries may match + given ARG but not SYMTAB's filename. */ + filename = arg; } e = XZALLOC (struct skiplist_entry); e->filename = xstrdup (filename); e->enabled = 1; - e->pending = pending; - if (symtab != 0) - e->gdbarch = get_objfile_arch (symtab->objfile); add_skiplist_entry (e); @@ -132,81 +113,41 @@ Ignore file pending future shared library load? "))) static void skip_function_command (char *arg, int from_tty) { - CORE_ADDR func_pc; - char *name = NULL; + const char *name = NULL; /* Default to the current function if no argument is given. */ - if (arg == 0) + if (arg == NULL) { CORE_ADDR pc; + if (!last_displayed_sal_is_valid ()) error (_("No default function now.")); pc = get_last_displayed_addr (); - if (!find_pc_partial_function (pc, &name, &func_pc, 0)) + if (!find_pc_partial_function (pc, &name, NULL, NULL)) { error (_("No function found containing current program point %s."), paddress (get_current_arch (), pc)); } - skip_function_pc (func_pc, name, get_current_arch (), 0); + skip_function (name); } else { - /* Decode arg. We set funfirstline=1 so decode_line_1 will give us the - first line of the function specified, if it can, and so that we'll - reject variable names and the like. */ - - int i; - int pending = 0; - char *orig_arg = arg; /* decode_line_1 modifies the arg pointer. */ - volatile struct gdb_exception decode_exception; - struct symtabs_and_lines sals = { 0 }; - - TRY_CATCH (decode_exception, RETURN_MASK_ERROR) - { - sals = decode_line_1 (&arg, DECODE_LINE_FUNFIRSTLINE, 0, 0); - } - - if (decode_exception.reason < 0) + if (lookup_symbol (arg, NULL, VAR_DOMAIN, NULL) == NULL) { - if (decode_exception.error != NOT_FOUND_ERROR) - throw_exception (decode_exception); - fprintf_filtered (gdb_stderr, - _("No function found named %s.\n"), orig_arg); + _("No function found named %s.\n"), arg); if (nquery (_("\ Ignore function pending future shared library load? "))) { - /* Add the pending skiplist entry. */ - skip_function_pc (0, orig_arg, 0, 1); + /* Add the unverified skiplist entry. */ + skip_function (arg); } - return; } - if (sals.nelts > 1) - error (_("Specify just one function at a time.")); - if (strlen (arg) != 0) - error (_("Junk at end of arguments.")); - - /* The pc decode_line_1 gives us is the first line of the function, - but we actually want the line before that. The call to - find_pc_partial_function gets us the value we actually want. */ - { - struct symtab_and_line sal = sals.sals[0]; - CORE_ADDR pc = sal.pc; - CORE_ADDR func_start = 0; - struct gdbarch *arch = get_sal_arch (sal); - - if (!find_pc_partial_function (pc, &name, &func_start, 0)) - { - error (_("No function found containing program point %s."), - paddress (arch, pc)); - } - - skip_function_pc (func_start, name, arch, 0); - } + skip_function (arg); } } @@ -215,7 +156,6 @@ skip_info (char *arg, int from_tty) { struct skiplist_entry *e; int num_printable_entries = 0; - int address_width = 10; struct value_print_options opts; struct cleanup *tbl_chain; @@ -224,16 +164,12 @@ skip_info (char *arg, int from_tty) /* Count the number of rows in the table and see if we need space for a 64-bit address anywhere. */ ALL_SKIPLIST_ENTRIES (e) - if (arg == 0 || number_is_in_list (arg, e->number)) - { - num_printable_entries++; - if (e->gdbarch && gdbarch_addr_bit (e->gdbarch) > 32) - address_width = 18; - } + if (arg == NULL || number_is_in_list (arg, e->number)) + num_printable_entries++; if (num_printable_entries == 0) { - if (arg == 0) + if (arg == NULL) ui_out_message (current_uiout, 0, _("\ Not skipping any files or functions.\n")); else @@ -243,25 +179,14 @@ Not skipping any files or functions.\n")); return; } - if (opts.addressprint) - tbl_chain = make_cleanup_ui_out_table_begin_end (current_uiout, 5, - num_printable_entries, - "SkiplistTable"); - else - tbl_chain - = make_cleanup_ui_out_table_begin_end (current_uiout, 4, - num_printable_entries, - "SkiplistTable"); + tbl_chain = make_cleanup_ui_out_table_begin_end (current_uiout, 4, + num_printable_entries, + "SkiplistTable"); ui_out_table_header (current_uiout, 7, ui_left, "number", "Num"); /* 1 */ ui_out_table_header (current_uiout, 14, ui_left, "type", "Type"); /* 2 */ ui_out_table_header (current_uiout, 3, ui_left, "enabled", "Enb"); /* 3 */ - if (opts.addressprint) - { - ui_out_table_header (current_uiout, address_width, ui_left, - "addr", "Address"); /* 4 */ - } - ui_out_table_header (current_uiout, 40, ui_noalign, "what", "What"); /* 5 */ + ui_out_table_header (current_uiout, 40, ui_noalign, "what", "What"); /* 4 */ ui_out_table_body (current_uiout); ALL_SKIPLIST_ENTRIES (e) @@ -269,16 +194,16 @@ Not skipping any files or functions.\n")); struct cleanup *entry_chain; QUIT; - if (arg != 0 && !number_is_in_list (arg, e->number)) + if (arg != NULL && !number_is_in_list (arg, e->number)) continue; entry_chain = make_cleanup_ui_out_tuple_begin_end (current_uiout, "blklst-entry"); ui_out_field_int (current_uiout, "number", e->number); /* 1 */ - if (e->function_name != 0) + if (e->function_name != NULL) ui_out_field_string (current_uiout, "type", "function"); /* 2 */ - else if (e->filename != 0) + else if (e->filename != NULL) ui_out_field_string (current_uiout, "type", "file"); /* 2 */ else internal_error (__FILE__, __LINE__, _("\ @@ -289,39 +214,10 @@ Skiplist entry should have either a filename or a function name.")); else ui_out_field_string (current_uiout, "enabled", "n"); /* 3 */ - if (opts.addressprint) - { - if (e->pc != 0) - ui_out_field_core_addr (current_uiout, "addr", - e->gdbarch, e->pc); /* 4 */ - else - ui_out_field_string (current_uiout, "addr", ""); /* 4 */ - } - - if (!e->pending && e->function_name != 0) - { - struct symbol *sym; - - gdb_assert (e->pc != 0); - sym = find_pc_function (e->pc); - if (sym) - ui_out_field_fmt (current_uiout, "what", "%s at %s:%d", - sym->ginfo.name, - sym->symtab->filename, - sym->line); - else - ui_out_field_string (current_uiout, "what", "?"); - } - else if (e->pending && e->function_name != 0) - { - ui_out_field_fmt (current_uiout, "what", "%s (PENDING)", - e->function_name); - } - else if (!e->pending && e->filename != 0) - ui_out_field_string (current_uiout, "what", e->filename); - else if (e->pending && e->filename != 0) - ui_out_field_fmt (current_uiout, "what", "%s (PENDING)", - e->filename); + if (e->function_name != NULL) + ui_out_field_string (current_uiout, "what", e->function_name); /* 4 */ + else if (e->filename != NULL) + ui_out_field_string (current_uiout, "what", e->filename); /* 4 */ ui_out_text (current_uiout, "\n"); do_cleanups (entry_chain); @@ -337,7 +233,7 @@ skip_enable_command (char *arg, int from_tty) int found = 0; ALL_SKIPLIST_ENTRIES (e) - if (arg == 0 || number_is_in_list (arg, e->number)) + if (arg == NULL || number_is_in_list (arg, e->number)) { e->enabled = 1; found = 1; @@ -354,7 +250,7 @@ skip_disable_command (char *arg, int from_tty) int found = 0; ALL_SKIPLIST_ENTRIES (e) - if (arg == 0 || number_is_in_list (arg, e->number)) + if (arg == NULL || number_is_in_list (arg, e->number)) { e->enabled = 0; found = 1; @@ -372,9 +268,9 @@ skip_delete_command (char *arg, int from_tty) b_prev = 0; ALL_SKIPLIST_ENTRIES_SAFE (e, temp) - if (arg == 0 || number_is_in_list (arg, e->number)) + if (arg == NULL || number_is_in_list (arg, e->number)) { - if (b_prev != 0) + if (b_prev != NULL) b_prev->next = e->next; else skiplist_entry_chain = e->next; @@ -393,30 +289,20 @@ skip_delete_command (char *arg, int from_tty) error (_("No skiplist entries found with number %s."), arg); } -/* Create a skiplist entry for the given pc corresponding to the given - function name and add it to the list. */ +/* Create a skiplist entry for the given function NAME and add it to the + list. */ static void -skip_function_pc (CORE_ADDR pc, char *name, struct gdbarch *arch, - int pending) +skip_function (const char *name) { struct skiplist_entry *e = XZALLOC (struct skiplist_entry); - e->pc = pc; - e->gdbarch = arch; e->enabled = 1; - e->pending = pending; e->function_name = xstrdup (name); add_skiplist_entry (e); - if (!pending) - printf_filtered (_("Function %s at %s will be skipped when stepping.\n"), - name, paddress (get_current_arch (), pc)); - else - printf_filtered (_("Function %s will be skipped when stepping, " - "pending shared library load.\n"), - name); + printf_filtered (_("Function %s will be skipped when stepping.\n"), name); } /* Add the given skiplist entry to our list, and set the entry's number. */ @@ -432,7 +318,7 @@ add_skiplist_entry (struct skiplist_entry *e) skiplist entries will be in numerical order. */ e1 = skiplist_entry_chain; - if (e1 == 0) + if (e1 == NULL) skiplist_entry_chain = e; else { @@ -442,37 +328,57 @@ add_skiplist_entry (struct skiplist_entry *e) } } -/* Does the given pc correspond to the beginning of a skipped function? */ + +/* See skip.h. */ int -function_pc_is_marked_for_skip (CORE_ADDR pc) +function_name_is_marked_for_skip (const char *function_name, + const struct symtab_and_line *function_sal) { - int searched_for_sal = 0; - struct symtab_and_line sal; - char *filename = NULL; + int searched_for_fullname = 0; + const char *fullname = NULL; struct skiplist_entry *e; + if (function_name == NULL) + return 0; + ALL_SKIPLIST_ENTRIES (e) { - if (!e->enabled || e->pending) + if (!e->enabled) continue; /* Does the pc we're stepping into match e's stored pc? */ - if (e->pc != 0 && pc == e->pc) + if (e->function_name != NULL + && strcmp_iw (function_name, e->function_name) == 0) return 1; - if (e->filename != 0) + if (e->filename != NULL) { - /* Get the filename corresponding to this pc, if we haven't - * yet. */ - if (!searched_for_sal) + /* Check first sole SYMTAB->FILENAME. It does not need to be + a substring of symtab_to_fullname as it may contain "./" etc. */ + if (function_sal->symtab != NULL + && compare_filenames_for_search (function_sal->symtab->filename, + e->filename)) + return 1; + + /* Before we invoke realpath, which can get expensive when many + files are involved, do a quick comparison of the basenames. */ + if (!basenames_may_differ + && (function_sal->symtab == NULL + || filename_cmp (lbasename (function_sal->symtab->filename), + lbasename (e->filename)) != 0)) + continue; + + /* Get the filename corresponding to this FUNCTION_SAL, if we haven't + yet. */ + if (!searched_for_fullname) { - sal = find_pc_line (pc, 0); - if (sal.symtab != 0) - filename = sal.symtab->filename; - searched_for_sal = 1; + if (function_sal->symtab != NULL) + fullname = symtab_to_fullname (function_sal->symtab); + searched_for_fullname = 1; } - if (filename != 0 && strcmp (filename, e->filename) == 0) + if (fullname != NULL + && compare_filenames_for_search (fullname, e->filename)) return 1; } } @@ -480,71 +386,13 @@ function_pc_is_marked_for_skip (CORE_ADDR pc) return 0; } -/* Re-set the skip list after symbols have been re-loaded. */ -void -skip_re_set (void) -{ - struct skiplist_entry *e; - - ALL_SKIPLIST_ENTRIES (e) - { - if (e->filename != 0) - { - /* If it's an entry telling us to skip a file, but the entry is - currently pending a solib load, let's see if we now know - about the file. */ - struct symtab *symtab = lookup_symtab (e->filename); - if (symtab != 0) - { - xfree (e->filename); - e->filename = xstrdup (symtab->filename); - e->gdbarch = get_objfile_arch (symtab->objfile); - e->pending = 0; - } - else - { - e->pending = 1; - } - } - else if (e->function_name != 0) - { - char *func_name = e->function_name; - struct symtabs_and_lines sals = { 0 }; - volatile struct gdb_exception decode_exception; - - TRY_CATCH (decode_exception, RETURN_MASK_ERROR) - { - sals = decode_line_1 (&func_name, DECODE_LINE_FUNFIRSTLINE, 0, 0); - } - - if (decode_exception.reason >= 0 - && sals.nelts == 1 && strlen (func_name) == 0) - { - struct symtab_and_line sal = sals.sals[0]; - CORE_ADDR pc = sal.pc; - CORE_ADDR func_start = 0; - struct gdbarch *arch = get_sal_arch (sal); - char *func_name; - - if (find_pc_partial_function (pc, &func_name, &func_start, 0)) - { - e->pending = 0; - e->function_name = xstrdup (func_name); - e->pc = func_start; - e->gdbarch = arch; - } - } - else - { - e->pending = 1; - } - } - } -} +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_step_skip; void _initialize_step_skip (void) { + static struct cmd_list_element *skiplist = NULL; struct cmd_list_element *c; skiplist_entry_chain = 0; diff --git a/contrib/gdb-7/gdb/skip.h b/contrib/gdb-7/gdb/skip.h index c1f8185460..9c5d257ac7 100644 --- a/contrib/gdb-7/gdb/skip.h +++ b/contrib/gdb-7/gdb/skip.h @@ -1,6 +1,6 @@ /* Header for skipping over uninteresting files and functions when debugging. - Copyright (C) 2011-2012 Free Software Foundation, Inc. + Copyright (C) 2011-2013 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 @@ -18,11 +18,11 @@ #if !defined (SKIP_H) #define SKIP_H -/* Returns 1 if the given pc is marked for skip and shouldn't be - stepped into. Otherwise, returns 0. */ -int function_pc_is_marked_for_skip (CORE_ADDR pc); +struct symtab_and_line; -/* Re-set the skip list after symbols have been reloaded. */ -void skip_re_set (void); +/* Returns 1 if the given FUNCTION_NAME is marked for skip and shouldn't be + stepped into. Otherwise, returns 0. */ +int function_name_is_marked_for_skip (const char *function_name, + const struct symtab_and_line *function_sal); #endif /* !defined (SKIP_H) */ diff --git a/contrib/gdb-7/gdb/solib-svr4.c b/contrib/gdb-7/gdb/solib-svr4.c index 69d3cb518e..0f70097e08 100644 --- a/contrib/gdb-7/gdb/solib-svr4.c +++ b/contrib/gdb-7/gdb/solib-svr4.c @@ -1,7 +1,6 @@ /* Handle SVR4 shared libraries for GDB, the GNU Debugger. - Copyright (C) 1990-1996, 1998-2001, 2003-2012 Free Software - Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -46,6 +45,7 @@ #include "exec.h" #include "auxv.h" #include "exceptions.h" +#include "gdb_bfd.h" static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); @@ -154,12 +154,12 @@ lm_info_read (CORE_ADDR lm_addr) if (target_read_memory (lm_addr, lm, lmo->link_map_size) != 0) { warning (_("Error reading shared library list entry at %s"), - paddress (target_gdbarch, lm_addr)), + paddress (target_gdbarch (), lm_addr)), lm_info = NULL; } else { - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; lm_info = xzalloc (sizeof (*lm_info)); lm_info->lm_addr = lm_addr; @@ -263,7 +263,7 @@ lm_addr_check (struct so_list *so, bfd *abfd) if (info_verbose) printf_unfiltered (_("Using PIC (Position Independent Code) " "prelink displacement %s for \"%s\".\n"), - paddress (target_gdbarch, l_addr), + paddress (target_gdbarch (), l_addr), so->so_name); } else @@ -362,7 +362,7 @@ static int match_main (const char *); static gdb_byte * read_program_header (int type, int *p_sect_size, int *p_arch_size) { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); CORE_ADDR at_phdr, at_phent, at_phnum, pt_phdr = 0; int arch_size, sect_size; CORE_ADDR sect_addr; @@ -611,7 +611,7 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr) gdb_byte ptr_buf[8]; CORE_ADDR ptr_addr; - ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + 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); @@ -631,7 +631,7 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr) static int scan_dyntag_auxv (int dyntag, CORE_ADDR *ptr) { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); int sect_size, arch_size, step; long dyn_tag; CORE_ADDR dyn_ptr; @@ -708,7 +708,7 @@ elf_locate_base (void) if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr) || scan_dyntag_auxv (DT_MIPS_RLD_MAP, &dyn_ptr)) { - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; gdb_byte *pbuf; int pbuf_size = TYPE_LENGTH (ptr_type); @@ -786,7 +786,7 @@ static CORE_ADDR solib_svr4_r_map (struct svr4_info *info) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; CORE_ADDR addr = 0; volatile struct gdb_exception ex; @@ -805,7 +805,7 @@ static CORE_ADDR solib_svr4_r_brk (struct svr4_info *info) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; return read_memory_typed_address (info->debug_base + lmo->r_brk_offset, ptr_type); @@ -818,8 +818,8 @@ static CORE_ADDR solib_svr4_r_ldsomap (struct svr4_info *info) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); ULONGEST version; /* Check version, and return zero if `struct r_debug' doesn't have @@ -848,7 +848,6 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) CORE_ADDR ldsomap; struct so_list *new; struct cleanup *old_chain; - struct link_map_offsets *lmo; CORE_ADDR name_lm; info = get_svr4_info (); @@ -862,7 +861,6 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) if (!ldsomap) return 0; - lmo = svr4_fetch_link_map_offsets (); new = XZALLOC (struct so_list); old_chain = make_cleanup (xfree, new); new->lm_info = lm_info_read (ldsomap); @@ -888,7 +886,7 @@ open_symbol_file_object (void *from_ttyp) int errcode; int from_tty = *(int *)from_ttyp; struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; int l_name_size = TYPE_LENGTH (ptr_type); gdb_byte *l_name_buf = xmalloc (l_name_size); struct cleanup *cleanups = make_cleanup (xfree, l_name_buf); @@ -979,7 +977,7 @@ svr4_free_library_list (void *p_list) { struct so_list *next = list->next; - svr4_free_so (list); + free_so (list); list = next; } } @@ -1175,7 +1173,6 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr, for (; lm != 0; prev_lm = lm, lm = next_lm) { - struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); struct so_list *new; struct cleanup *old_chain; int errcode; @@ -1196,8 +1193,8 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr, if (new->lm_info->l_prev != prev_lm) { warning (_("Corrupted shared library list: %s != %s"), - paddress (target_gdbarch, prev_lm), - paddress (target_gdbarch, new->lm_info->l_prev)); + paddress (target_gdbarch (), prev_lm), + paddress (target_gdbarch (), new->lm_info->l_prev)); do_cleanups (old_chain); break; } @@ -1260,6 +1257,14 @@ svr4_current_sos (void) int ignore_first; struct svr4_library_list library_list; + /* Fall back to manual examination of the target if the packet is not + supported or gdbserver failed to find DT_DEBUG. gdb.server/solib-list.exp + tests a case where gdbserver cannot find the shared libraries list while + GDB itself is able to find it via SYMFILE_OBJFILE. + + Unfortunately statically linked inferiors will also fall back through this + suboptimal code path. */ + if (svr4_current_sos_via_xfer_libraries (&library_list)) { if (library_list.main_lm) @@ -1379,6 +1384,8 @@ svr4_in_dynsym_resolve_code (CORE_ADDR pc) static CORE_ADDR exec_entry_point (struct bfd *abfd, struct target_ops *targ) { + CORE_ADDR addr; + /* KevinB wrote ... for most targets, the address returned by bfd_get_start_address() is the entry point for the start function. But, for some targets, bfd_get_start_address() returns @@ -1387,9 +1394,10 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ) gdbarch_convert_from_func_ptr_addr(). The method gdbarch_convert_from_func_ptr_addr() is the merely the identify function for targets which don't use function descriptors. */ - return gdbarch_convert_from_func_ptr_addr (target_gdbarch, + addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), bfd_get_start_address (abfd), targ); + return gdbarch_addr_bits_remove (target_gdbarch (), addr); } /* Helper function for gdb_bfd_lookup_symbol. */ @@ -1459,7 +1467,7 @@ enable_break (struct svr4_info *info, int from_tty) struct obj_section *os; sym_addr = gdbarch_addr_bits_remove - (target_gdbarch, gdbarch_convert_from_func_ptr_addr (target_gdbarch, + (target_gdbarch (), gdbarch_convert_from_func_ptr_addr (target_gdbarch (), sym_addr, ¤t_target)); @@ -1492,7 +1500,7 @@ enable_break (struct svr4_info *info, int from_tty) tmp_bfd = os->objfile->obfd; load_addr = ANOFFSET (os->objfile->section_offsets, - os->objfile->sect_index_text); + SECT_OFF_TEXT (os->objfile)); interp_sect = bfd_get_section_by_name (tmp_bfd, ".text"); if (interp_sect) @@ -1513,7 +1521,7 @@ enable_break (struct svr4_info *info, int from_tty) + bfd_section_size (tmp_bfd, interp_sect); } - create_solib_event_breakpoint (target_gdbarch, sym_addr); + create_solib_event_breakpoint (target_gdbarch (), sym_addr); return 1; } } @@ -1550,9 +1558,11 @@ enable_break (struct svr4_info *info, int from_tty) goto bkpt_at_symbol; /* Now convert the TMP_BFD into a target. That way target, as - well as BFD operations can be used. Note that closing the - target will also close the underlying bfd. */ + well as BFD operations can be used. */ tmp_bfd_target = target_bfd_reopen (tmp_bfd); + /* target_bfd_reopen acquired its own reference, so we can + release ours now. */ + gdb_bfd_unref (tmp_bfd); /* On a running target, we can get the dynamic linker's base address from the shared library table. */ @@ -1574,7 +1584,7 @@ enable_break (struct svr4_info *info, int from_tty) if (!load_addr_found) if (target_auxv_search (¤t_target, AT_BASE, &load_addr) > 0) { - int addr_bit = gdbarch_addr_bit (target_gdbarch); + int addr_bit = gdbarch_addr_bit (target_gdbarch ()); /* Ensure LOAD_ADDR has proper sign in its possible upper bits so that `+ load_addr' will overflow CORE_ADDR width not creating @@ -1610,7 +1620,7 @@ enable_break (struct svr4_info *info, int from_tty) if (!load_addr_found) { struct regcache *regcache - = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + = get_thread_arch_regcache (inferior_ptid, target_gdbarch ()); load_addr = (regcache_read_pc (regcache) - exec_entry_point (tmp_bfd, tmp_bfd_target)); @@ -1658,17 +1668,18 @@ enable_break (struct svr4_info *info, int from_tty) /* Convert 'sym_addr' from a function pointer to an address. Because we pass tmp_bfd_target instead of the current target, this will always produce an unrelocated value. */ - sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, + sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), sym_addr, tmp_bfd_target); - /* We're done with both the temporary bfd and target. Remember, - closing the target closes the underlying bfd. */ + /* We're done with both the temporary bfd and target. Closing + the target closes the underlying bfd, because it holds the + only remaining reference. */ target_close (tmp_bfd_target, 0); if (sym_addr != 0) { - create_solib_event_breakpoint (target_gdbarch, load_addr + sym_addr); + create_solib_event_breakpoint (target_gdbarch (), load_addr + sym_addr); xfree (interp_name); return 1; } @@ -1691,15 +1702,15 @@ enable_break (struct svr4_info *info, int from_tty) if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) { sym_addr = SYMBOL_VALUE_ADDRESS (msymbol); - sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, + sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), sym_addr, ¤t_target); - create_solib_event_breakpoint (target_gdbarch, sym_addr); + create_solib_event_breakpoint (target_gdbarch (), sym_addr); return 1; } } - if (!current_inferior ()->attach_flag) + if (interp_name != NULL && !current_inferior ()->attach_flag) { for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++) { @@ -1707,10 +1718,10 @@ enable_break (struct svr4_info *info, int from_tty) if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) { sym_addr = SYMBOL_VALUE_ADDRESS (msymbol); - sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, + sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), sym_addr, ¤t_target); - create_solib_event_breakpoint (target_gdbarch, sym_addr); + create_solib_event_breakpoint (target_gdbarch (), sym_addr); return 1; } } @@ -1851,7 +1862,7 @@ svr4_exec_displacement (CORE_ADDR *displacementp) buf2 = read_program_headers_from_bfd (exec_bfd, &phdrs2_size); if (buf != NULL && buf2 != NULL) { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); /* We are dealing with three different addresses. EXEC_BFD represents current address in on-disk file. target memory content @@ -2106,7 +2117,7 @@ svr4_exec_displacement (CORE_ADDR *displacementp) printf_unfiltered (_("Using PIE (Position Independent Executable) " "displacement %s for \"%s\".\n"), - paddress (target_gdbarch, displacement), + paddress (target_gdbarch (), displacement), bfd_get_filename (exec_bfd)); } @@ -2197,25 +2208,11 @@ svr4_relocate_main_executable (void) This function is responsible for discovering those names and addresses, and saving sufficient information about them to allow - their symbols to be read at a later time. - - FIXME - - Between enable_break() and disable_break(), this code does not - properly handle hitting breakpoints which the user might have - set in the startup code or in the dynamic linker itself. Proper - handling will probably have to wait until the implementation is - changed to use the "breakpoint handler function" method. - - Also, what if child has exit()ed? Must exit loop somehow. */ + their symbols to be read at a later time. */ static void svr4_solib_create_inferior_hook (int from_tty) { -#if defined(_SCO_DS) - struct inferior *inf; - struct thread_info *tp; -#endif /* defined(_SCO_DS) */ struct svr4_info *info; info = get_svr4_info (); @@ -2233,31 +2230,6 @@ svr4_solib_create_inferior_hook (int from_tty) if (!enable_break (info, from_tty)) return; - -#if defined(_SCO_DS) - /* SCO needs the loop below, other systems should be using the - special shared library breakpoints and the shared library breakpoint - service routine. - - Now run the target. It will eventually hit the breakpoint, at - which point all of the libraries will have been mapped in and we - can go groveling around in the dynamic linker structures to find - out what we need to know about them. */ - - inf = current_inferior (); - tp = inferior_thread (); - - clear_proceed_status (); - inf->control.stop_soon = STOP_QUIETLY; - tp->suspend.stop_signal = TARGET_SIGNAL_0; - do - { - target_resume (pid_to_ptid (-1), 0, tp->suspend.stop_signal); - wait_for_inferior (); - } - while (tp->suspend.stop_signal != TARGET_SIGNAL_TRAP); - inf->control.stop_soon = NO_STOP_QUIETLY; -#endif /* defined(_SCO_DS) */ } static void @@ -2289,12 +2261,12 @@ svr4_clear_solib (void) static CORE_ADDR svr4_truncate_ptr (CORE_ADDR addr) { - if (gdbarch_ptr_bit (target_gdbarch) == sizeof (CORE_ADDR) * 8) + if (gdbarch_ptr_bit (target_gdbarch ()) == sizeof (CORE_ADDR) * 8) /* We don't need to truncate anything, and the bit twiddling below will fail due to overflow problems. */ return addr; else - return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (target_gdbarch)) - 1); + return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (target_gdbarch ())) - 1); } @@ -2352,7 +2324,7 @@ set_solib_svr4_fetch_link_map_offsets (struct gdbarch *gdbarch, static struct link_map_offsets * svr4_fetch_link_map_offsets (void) { - struct solib_svr4_ops *ops = gdbarch_data (target_gdbarch, solib_svr4_data); + struct solib_svr4_ops *ops = gdbarch_data (target_gdbarch (), solib_svr4_data); gdb_assert (ops->fetch_link_map_offsets); return ops->fetch_link_map_offsets (); @@ -2363,7 +2335,7 @@ svr4_fetch_link_map_offsets (void) static int svr4_have_link_map_offsets (void) { - struct solib_svr4_ops *ops = gdbarch_data (target_gdbarch, solib_svr4_data); + struct solib_svr4_ops *ops = gdbarch_data (target_gdbarch (), solib_svr4_data); return (ops->fetch_link_map_offsets != NULL); } @@ -2472,7 +2444,7 @@ _initialize_svr4_solib (void) { solib_svr4_data = gdbarch_data_register_pre_init (solib_svr4_init); solib_svr4_pspace_data - = register_program_space_data_with_cleanup (svr4_pspace_data_cleanup); + = register_program_space_data_with_cleanup (NULL, svr4_pspace_data_cleanup); svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses; svr4_so_ops.free_so = svr4_free_so; diff --git a/contrib/gdb-7/gdb/solib-svr4.h b/contrib/gdb-7/gdb/solib-svr4.h index f9a02c9b50..66a06e1391 100644 --- a/contrib/gdb-7/gdb/solib-svr4.h +++ b/contrib/gdb-7/gdb/solib-svr4.h @@ -1,6 +1,6 @@ /* Handle shared libraries for GDB, the GNU Debugger. - Copyright (C) 2000, 2004, 2006-2012 Free Software Foundation, Inc. + Copyright (C) 2000-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/solib-target.c b/contrib/gdb-7/gdb/solib-target.c index 0f3f850a6e..d897bc0f27 100644 --- a/contrib/gdb-7/gdb/solib-target.c +++ b/contrib/gdb-7/gdb/solib-target.c @@ -1,6 +1,6 @@ /* Definitions for targets which report shared library events. - Copyright (C) 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2007-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -246,7 +246,8 @@ static struct so_list * solib_target_current_sos (void) { struct so_list *new_solib, *start = NULL, *last = NULL; - const char *library_document; + char *library_document; + struct cleanup *old_chain; VEC(lm_info_p) *library_list; struct lm_info *info; int ix; @@ -258,8 +259,15 @@ solib_target_current_sos (void) if (library_document == NULL) return NULL; + /* solib_target_parse_libraries may throw, so we use a cleanup. */ + old_chain = make_cleanup (xfree, library_document); + /* Parse the list. */ library_list = solib_target_parse_libraries (library_document); + + /* library_document string is not needed behind this point. */ + do_cleanups (old_chain); + if (library_list == NULL) return NULL; @@ -325,7 +333,6 @@ static void solib_target_relocate_section_addresses (struct so_list *so, struct target_section *sec) { - int flags = bfd_get_section_flags (sec->bfd, sec->the_bfd_section); CORE_ADDR offset; /* Build the offset table only once per object file. We can not do diff --git a/contrib/gdb-7/gdb/solib-target.h b/contrib/gdb-7/gdb/solib-target.h index f3e7d74249..4b9c3bb1c6 100644 --- a/contrib/gdb-7/gdb/solib-target.h +++ b/contrib/gdb-7/gdb/solib-target.h @@ -1,6 +1,6 @@ /* Handle shared libraries for GDB, the GNU Debugger. - Copyright (C) 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2007-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/solib.c b/contrib/gdb-7/gdb/solib.c index f5917856d1..8129c0fb52 100644 --- a/contrib/gdb-7/gdb/solib.c +++ b/contrib/gdb-7/gdb/solib.c @@ -1,6 +1,6 @@ /* Handle shared libraries for GDB, the GNU Debugger. - Copyright (C) 1990-2003, 2005-2012 Free Software Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -46,6 +46,7 @@ #include "solib.h" #include "interps.h" #include "filesystem.h" +#include "gdb_bfd.h" /* Architecture-specific operations. */ @@ -142,12 +143,12 @@ show_solib_search_path (struct ui_file *file, int from_tty, char * solib_find (char *in_pathname, int *fd) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); int found_file = -1; char *temp_pathname = NULL; int gdb_sysroot_is_empty; const char *solib_symbols_extension - = gdbarch_solib_symbols_extension (target_gdbarch); + = gdbarch_solib_symbols_extension (target_gdbarch ()); const char *fskind = effective_target_file_system_kind (); struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); char *sysroot = NULL; @@ -299,11 +300,6 @@ solib_find (char *in_pathname, int *fd) if (found_file < 0) temp_pathname = NULL; - /* If not found, search the solib_search_path (if any). */ - if (found_file < 0 && solib_search_path != NULL) - found_file = openp (solib_search_path, OPF_TRY_CWD_FIRST, - in_pathname, O_RDONLY | O_BINARY, &temp_pathname); - /* If the search in gdb_sysroot failed, and the path name is absolute at this point, make it relative. (openp will try and open the file according to its absolute path otherwise, which is not what we want.) @@ -360,9 +356,9 @@ solib_find (char *in_pathname, int *fd) it is used as file handle to open the file. Throws an error if the file could not be opened. Handles both local and remote file access. - PATHNAME must be malloc'ed by the caller. If successful, the new BFD's - name will point to it. If unsuccessful, PATHNAME will be freed and the - FD will be closed (unless FD was -1). */ + PATHNAME must be malloc'ed by the caller. It will be freed by this + function. If unsuccessful, the FD will be closed (unless FD was + -1). */ bfd * solib_bfd_fopen (char *pathname, int fd) @@ -376,12 +372,10 @@ solib_bfd_fopen (char *pathname, int fd) } else { - abfd = bfd_fopen (pathname, gnutarget, FOPEN_RB, fd); + abfd = gdb_bfd_open (pathname, gnutarget, fd); if (abfd) bfd_set_cacheable (abfd, 1); - else if (fd != -1) - close (fd); } if (!abfd) @@ -391,6 +385,8 @@ solib_bfd_fopen (char *pathname, int fd) pathname, bfd_errmsg (bfd_get_error ())); } + xfree (pathname); + return abfd; } @@ -422,17 +418,16 @@ solib_bfd_open (char *pathname) /* Check bfd format. */ if (!bfd_check_format (abfd, bfd_object)) { - bfd_close (abfd); - make_cleanup (xfree, found_pathname); + make_cleanup_bfd_unref (abfd); error (_("`%s': not in executable format: %s"), - found_pathname, bfd_errmsg (bfd_get_error ())); + bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); } /* Check bfd arch. */ - b = gdbarch_bfd_arch_info (target_gdbarch); + b = gdbarch_bfd_arch_info (target_gdbarch ()); if (!b->compatible (b, bfd_get_arch_info (abfd))) warning (_("`%s': Shared library architecture %s is not compatible " - "with target architecture %s."), found_pathname, + "with target architecture %s."), bfd_get_filename (abfd), bfd_get_arch_info (abfd)->printable_name, b->printable_name); return abfd; @@ -453,7 +448,7 @@ solib_bfd_open (char *pathname) static int solib_map_sections (struct so_list *so) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); char *filename; struct target_section *p; struct cleanup *old_chain; @@ -468,7 +463,7 @@ solib_map_sections (struct so_list *so) return 0; /* Leave bfd open, core_xfer_memory and "info files" need it. */ - so->abfd = gdb_bfd_ref (abfd); + so->abfd = abfd; /* copy full path name into so_name, so that later symbol_file_add can find it. */ @@ -504,7 +499,7 @@ solib_map_sections (struct so_list *so) section tables. 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. */ - add_target_sections (so->sections, so->sections_end); + add_target_sections (so, so->sections, so->sections_end); return 1; } @@ -554,7 +549,7 @@ free_so_symbols (struct so_list *so) void free_so (struct so_list *so) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); free_so_symbols (so); ops->free_so (so); @@ -592,6 +587,8 @@ solib_read_symbols (struct so_list *so, int flags) { volatile struct gdb_exception e; + flags |= current_inferior ()->symfile_flags; + TRY_CATCH (e, RETURN_MASK_ERROR) { struct section_addr_info *sap; @@ -671,7 +668,7 @@ solib_used (const struct so_list *const known) static void update_solib_list (int from_tty, struct target_ops *target) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); struct so_list *inferior = ops->current_sos(); struct so_list *gdb, **gdb_link; @@ -758,6 +755,9 @@ update_solib_list (int from_tty, struct target_ops *target) unloaded before we remove it from GDB's tables. */ observer_notify_solib_unloaded (gdb); + VEC_safe_push (char_ptr, current_program_space->deleted_solibs, + xstrdup (gdb->so_name)); + *gdb_link = gdb->next; /* Unless the user loaded it explicitly, free SO's objfile. */ @@ -767,7 +767,7 @@ update_solib_list (int from_tty, struct target_ops *target) /* Some targets' section tables might be referring to sections from so->abfd; remove them. */ - remove_target_sections (gdb->abfd); + remove_target_sections (gdb, gdb->abfd); free_so (gdb); gdb = *gdb_link; @@ -793,6 +793,7 @@ update_solib_list (int from_tty, struct target_ops *target) volatile struct gdb_exception e; i->pspace = current_program_space; + VEC_safe_push (so_list_ptr, current_program_space->added_solibs, i); TRY_CATCH (e, RETURN_MASK_ERROR) { @@ -929,7 +930,7 @@ solib_add (char *pattern, int from_tty, if (loaded_any_symbols) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); /* Getting new symbols may change our opinion about what is frameless. */ @@ -953,7 +954,7 @@ info_sharedlibrary_command (char *pattern, int from_tty) int addr_width; int nr_libs; struct cleanup *table_cleanup; - struct gdbarch *gdbarch = target_gdbarch; + struct gdbarch *gdbarch = target_gdbarch (); struct ui_out *uiout = current_uiout; if (pattern) @@ -1102,7 +1103,7 @@ solib_name_from_address (struct program_space *pspace, CORE_ADDR address) int solib_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); if (ops->keep_data_in_core) return ops->keep_data_in_core (vaddr, size); @@ -1115,7 +1116,7 @@ solib_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) void clear_solib (void) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); /* This function is expected to handle ELF shared libraries. It is also used on Solaris, which can run either ELF or a.out binaries @@ -1148,7 +1149,7 @@ clear_solib (void) so_list_head = so->next; observer_notify_solib_unloaded (so); if (so->abfd) - remove_target_sections (so->abfd); + remove_target_sections (so, so->abfd); free_so (so); } @@ -1163,7 +1164,7 @@ clear_solib (void) void solib_create_inferior_hook (int from_tty) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); ops->solib_create_inferior_hook (from_tty); } @@ -1174,7 +1175,7 @@ solib_create_inferior_hook (int from_tty) int in_solib_dynsym_resolve_code (CORE_ADDR pc) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); return ops->in_dynsym_resolve_code (pc); } @@ -1229,7 +1230,7 @@ reload_shared_libraries_1 (int from_tty) { found_pathname = xstrdup (bfd_get_filename (abfd)); make_cleanup (xfree, found_pathname); - gdb_bfd_close_or_warn (abfd); + gdb_bfd_unref (abfd); } /* If this shared library is no longer associated with its previous @@ -1241,7 +1242,7 @@ reload_shared_libraries_1 (int from_tty) if (so->objfile && ! (so->objfile->flags & OBJF_USERLOADED) && !solib_used (so)) free_objfile (so->objfile); - remove_target_sections (so->abfd); + remove_target_sections (so, so->abfd); free_so_symbols (so); } @@ -1276,7 +1277,7 @@ reload_shared_libraries (char *ignored, int from_tty, reload_shared_libraries_1 (from_tty); - ops = solib_ops (target_gdbarch); + ops = solib_ops (target_gdbarch ()); /* Creating inferior hooks here has two purposes. First, if we reload shared libraries then the address of solib breakpoint we've computed @@ -1343,7 +1344,7 @@ solib_global_lookup (const struct objfile *objfile, const char *name, const domain_enum domain) { - struct target_so_ops *ops = solib_ops (target_gdbarch); + struct target_so_ops *ops = solib_ops (target_gdbarch ()); if (ops->lookup_lib_global_symbol != NULL) return ops->lookup_lib_global_symbol (objfile, name, domain); diff --git a/contrib/gdb-7/gdb/solib.h b/contrib/gdb-7/gdb/solib.h index 2c7f4d9256..b811866f7f 100644 --- a/contrib/gdb-7/gdb/solib.h +++ b/contrib/gdb-7/gdb/solib.h @@ -1,7 +1,6 @@ /* Shared library declarations for GDB, the GNU Debugger. - Copyright (C) 1992-1993, 1995, 1998-2001, 2003, 2005, 2007-2012 Free - Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -86,9 +85,9 @@ extern CORE_ADDR gdb_bfd_lookup_symbol (bfd *abfd, /* Look up symbol from symbol table. */ -extern CORE_ADDR bfd_lookup_symbol_from_symtab (bfd *abfd, - int (*match_sym) (asymbol *, - void *), - void *data); +extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd, + int (*match_sym) (asymbol *, + void *), + void *data); #endif /* SOLIB_H */ diff --git a/contrib/gdb-7/gdb/solist.h b/contrib/gdb-7/gdb/solist.h index 7413e3b845..f784fc349e 100644 --- a/contrib/gdb-7/gdb/solist.h +++ b/contrib/gdb-7/gdb/solist.h @@ -1,6 +1,5 @@ /* Shared library declarations for GDB, the GNU Debugger. - Copyright (C) 1990-1996, 1998-2001, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. This file is part of GDB. diff --git a/contrib/gdb-7/gdb/somread.c b/contrib/gdb-7/gdb/somread.c new file mode 100644 index 0000000000..d9d3e7bb72 --- /dev/null +++ b/contrib/gdb-7/gdb/somread.c @@ -0,0 +1,433 @@ +/* Read HP PA/Risc object files for GDB. + Copyright (C) 1991-2013 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support. + + 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 "bfd.h" +#include "som/aout.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "stabsread.h" +#include "gdb-stabs.h" +#include "complaints.h" +#include "gdb_string.h" +#include "demangle.h" +#include "som.h" +#include "libhppa.h" +#include "psymtab.h" + +#include "solib-som.h" + +/* Read the symbol table of a SOM file. + + Given an open bfd, a base address to relocate symbols to, and a + flag that specifies whether or not this bfd is for an executable + or not (may be shared library for example), add all the global + function and data symbols to the minimal symbol table. */ + +static void +som_symtab_read (bfd *abfd, struct objfile *objfile, + struct section_offsets *section_offsets) +{ + struct gdbarch *gdbarch = get_objfile_arch (objfile); + unsigned int number_of_symbols; + int val, dynamic; + char *stringtab; + asection *shlib_info; + struct som_external_symbol_dictionary_record *buf, *bufp, *endbufp; + char *symname; + CONST int symsize = sizeof (struct som_external_symbol_dictionary_record); + CORE_ADDR text_offset, data_offset; + + + text_offset = ANOFFSET (section_offsets, 0); + data_offset = ANOFFSET (section_offsets, 1); + + number_of_symbols = bfd_get_symcount (abfd); + + /* Allocate a buffer to read in the debug info. + We avoid using alloca because the memory size could be so large + that we could hit the stack size limit. */ + buf = xmalloc (symsize * number_of_symbols); + make_cleanup (xfree, buf); + bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET); + val = bfd_bread (buf, symsize * number_of_symbols, abfd); + if (val != symsize * number_of_symbols) + error (_("Couldn't read symbol dictionary!")); + + /* Allocate a buffer to read in the som stringtab section of + the debugging info. Again, we avoid using alloca because + the data could be so large that we could potentially hit + the stack size limitat. */ + stringtab = xmalloc (obj_som_stringtab_size (abfd)); + make_cleanup (xfree, stringtab); + bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET); + val = bfd_bread (stringtab, obj_som_stringtab_size (abfd), abfd); + if (val != obj_som_stringtab_size (abfd)) + error (_("Can't read in HP string table.")); + + /* We need to determine if objfile is a dynamic executable (so we + can do the right thing for ST_ENTRY vs ST_CODE symbols). + + There's nothing in the header which easily allows us to do + this. + + This code used to rely upon the existence of a $SHLIB_INFO$ + section to make this determination. HP claims that it is + more accurate to check for a nonzero text offset, but they + have not provided any information about why that test is + more accurate. */ + dynamic = (text_offset != 0); + + endbufp = buf + number_of_symbols; + for (bufp = buf; bufp < endbufp; ++bufp) + { + enum minimal_symbol_type ms_type; + unsigned int flags = bfd_getb32 (bufp->flags); + unsigned int symbol_type + = (flags >> SOM_SYMBOL_TYPE_SH) & SOM_SYMBOL_TYPE_MASK; + unsigned int symbol_scope + = (flags >> SOM_SYMBOL_SCOPE_SH) & SOM_SYMBOL_SCOPE_MASK; + CORE_ADDR symbol_value = bfd_getb32 (bufp->symbol_value); + + QUIT; + + switch (symbol_scope) + { + case SS_UNIVERSAL: + case SS_EXTERNAL: + switch (symbol_type) + { + case ST_SYM_EXT: + case ST_ARG_EXT: + continue; + + case ST_CODE: + case ST_PRI_PROG: + case ST_SEC_PROG: + case ST_MILLICODE: + symname = bfd_getb32 (bufp->name) + stringtab; + ms_type = mst_text; + symbol_value += text_offset; + symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); + break; + + case ST_ENTRY: + symname = bfd_getb32 (bufp->name) + stringtab; + /* For a dynamic executable, ST_ENTRY symbols are + the stubs, while the ST_CODE symbol is the real + function. */ + if (dynamic) + ms_type = mst_solib_trampoline; + else + ms_type = mst_text; + symbol_value += text_offset; + symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); + break; + + case ST_STUB: + symname = bfd_getb32 (bufp->name) + stringtab; + ms_type = mst_solib_trampoline; + symbol_value += text_offset; + symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); + break; + + case ST_DATA: + symname = bfd_getb32 (bufp->name) + stringtab; + symbol_value += data_offset; + ms_type = mst_data; + break; + default: + continue; + } + break; + +#if 0 + /* SS_GLOBAL and SS_LOCAL are two names for the same thing (!). */ + case SS_GLOBAL: +#endif + case SS_LOCAL: + switch (symbol_type) + { + case ST_SYM_EXT: + case ST_ARG_EXT: + continue; + + case ST_CODE: + symname = bfd_getb32 (bufp->name) + stringtab; + ms_type = mst_file_text; + symbol_value += text_offset; + symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); + + check_strange_names: + /* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local + label prefixes for stabs, constant data, etc. So we need + only filter out L$ symbols which are left in due to + limitations in how GAS generates SOM relocations. + + When linking in the HPUX C-library the HP linker has + the nasty habit of placing section symbols from the literal + subspaces in the middle of the program's text. Filter + those out as best we can. Check for first and last character + being '$'. + + And finally, the newer HP compilers emit crud like $PIC_foo$N + in some circumstance (PIC code I guess). It's also claimed + that they emit D$ symbols too. What stupidity. */ + if ((symname[0] == 'L' && symname[1] == '$') + || (symname[0] == '$' && symname[strlen (symname) - 1] == '$') + || (symname[0] == 'D' && symname[1] == '$') + || (strncmp (symname, "L0\001", 3) == 0) + || (strncmp (symname, "$PIC", 4) == 0)) + continue; + break; + + case ST_PRI_PROG: + case ST_SEC_PROG: + case ST_MILLICODE: + symname = bfd_getb32 (bufp->name) + stringtab; + ms_type = mst_file_text; + symbol_value += text_offset; + symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); + break; + + case ST_ENTRY: + symname = bfd_getb32 (bufp->name) + stringtab; + /* SS_LOCAL symbols in a shared library do not have + export stubs, so we do not have to worry about + using mst_file_text vs mst_solib_trampoline here like + we do for SS_UNIVERSAL and SS_EXTERNAL symbols above. */ + ms_type = mst_file_text; + symbol_value += text_offset; + symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); + break; + + case ST_STUB: + symname = bfd_getb32 (bufp->name) + stringtab; + ms_type = mst_solib_trampoline; + symbol_value += text_offset; + symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); + break; + + + case ST_DATA: + symname = bfd_getb32 (bufp->name) + stringtab; + symbol_value += data_offset; + ms_type = mst_file_data; + goto check_strange_names; + + default: + continue; + } + break; + + /* This can happen for common symbols when -E is passed to the + final link. No idea _why_ that would make the linker force + common symbols to have an SS_UNSAT scope, but it does. + + This also happens for weak symbols, but their type is + ST_DATA. */ + case SS_UNSAT: + switch (symbol_type) + { + case ST_STORAGE: + case ST_DATA: + symname = bfd_getb32 (bufp->name) + stringtab; + symbol_value += data_offset; + ms_type = mst_data; + break; + + default: + continue; + } + break; + + default: + continue; + } + + if (bfd_getb32 (bufp->name) > obj_som_stringtab_size (abfd)) + error (_("Invalid symbol data; bad HP string table offset: %s"), + plongest (bfd_getb32 (bufp->name))); + + prim_record_minimal_symbol (symname, symbol_value, ms_type, objfile); + } +} + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to som_symfile_init, which + currently does nothing. + + SECTION_OFFSETS is a set of offsets to apply to relocate the symbols + in each section. This is ignored, as it isn't needed for SOM. + + This function only does the minimum work necessary for letting the + user "name" things symbolically; it does not read the entire symtab. + Instead, it reads the external and static symbols and puts them in partial + symbol tables. When more extensive information is requested of a + file, the corresponding partial symbol table is mutated into a full + fledged symbol table by going back and reading the symbols + for real. + + We look for sections with specific names, to tell us what debug + format to look for: FIXME!!! + + somstab_build_psymtabs() handles STABS symbols. + + Note that SOM files have a "minimal" symbol table, which is vaguely + reminiscent of a COFF symbol table, but has only the minimal information + necessary for linking. We process this also, and use the information to + build gdb's minimal symbol table. This gives us some minimal debugging + capability even for files compiled without -g. */ + +static void +som_symfile_read (struct objfile *objfile, int symfile_flags) +{ + bfd *abfd = objfile->obfd; + struct cleanup *back_to; + + init_minimal_symbol_collection (); + back_to = make_cleanup_discard_minimal_symbols (); + + /* Process the normal SOM symbol table first. + This reads in the DNTT and string table, but doesn't + actually scan the DNTT. It does scan the linker symbol + table and thus build up a "minimal symbol table". */ + + som_symtab_read (abfd, objfile, objfile->section_offsets); + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. + Further symbol-reading is done incrementally, file-by-file, + in a step known as "psymtab-to-symtab" expansion. hp-symtab-read.c + contains the code to do the actual DNTT scanning and symtab building. */ + install_minimal_symbols (objfile); + do_cleanups (back_to); + + /* Now read information from the stabs debug sections. + This is emitted by gcc. */ + stabsect_build_psymtabs (objfile, + "$GDB_SYMBOLS$", "$GDB_STRINGS$", "$TEXT$"); +} + +/* Initialize anything that needs initializing when a completely new symbol + file is specified (not just adding some symbols from another file, e.g. a + shared library). + + We reinitialize buildsym, since we may be reading stabs from a SOM file. */ + +static void +som_new_init (struct objfile *ignore) +{ + stabsread_new_init (); + buildsym_new_init (); +} + +/* Perform any local cleanups required when we are done with a particular + objfile. I.e, we are in the process of discarding all symbol information + for an objfile, freeing up all memory held for it, and unlinking the + objfile struct from the global list of known objfiles. */ + +static void +som_symfile_finish (struct objfile *objfile) +{ +} + +/* SOM specific initialization routine for reading symbols. */ + +static void +som_symfile_init (struct objfile *objfile) +{ + /* SOM objects may be reordered, so set OBJF_REORDERED. If we + find this causes a significant slowdown in gdb then we could + set it in the debug symbol readers only when necessary. */ + objfile->flags |= OBJF_REORDERED; +} + +/* SOM specific parsing routine for section offsets. + + Plain and simple for now. */ + +static void +som_symfile_offsets (struct objfile *objfile, struct section_addr_info *addrs) +{ + int i; + CORE_ADDR text_addr; + + objfile->num_sections = bfd_count_sections (objfile->obfd); + objfile->section_offsets = (struct section_offsets *) + obstack_alloc (&objfile->objfile_obstack, + SIZEOF_N_SECTION_OFFSETS (objfile->num_sections)); + + /* FIXME: ezannoni 2000-04-20 The section names in SOM are not + .text, .data, etc, but $TEXT$, $DATA$,... We should initialize + SET_OFF_* from bfd. (See default_symfile_offsets()). But I don't + know the correspondence between SOM sections and GDB's idea of + section names. So for now we default to what is was before these + changes. */ + objfile->sect_index_text = 0; + objfile->sect_index_data = 1; + objfile->sect_index_bss = 2; + objfile->sect_index_rodata = 3; + + /* First see if we're a shared library. If so, get the section + offsets from the library, else get them from addrs. */ + if (!som_solib_section_offsets (objfile, objfile->section_offsets)) + { + /* Note: Here is OK to compare with ".text" because this is the + name that gdb itself gives to that section, not the SOM + name. */ + for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++) + if (strcmp (addrs->other[i].name, ".text") == 0) + break; + text_addr = addrs->other[i].addr; + + for (i = 0; i < objfile->num_sections; i++) + (objfile->section_offsets)->offsets[i] = text_addr; + } +} + + + +/* Register that we are able to handle SOM object file formats. */ + +static const struct sym_fns som_sym_fns = +{ + bfd_target_som_flavour, + som_new_init, /* init anything gbl to entire symtab */ + som_symfile_init, /* read initial info, setup for sym_read() */ + som_symfile_read, /* read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ + som_symfile_finish, /* finished with file, cleanup */ + som_symfile_offsets, /* Translate ext. to int. relocation */ + default_symfile_segments, /* Get segment information from a file. */ + NULL, + default_symfile_relocate, /* Relocate a debug section. */ + NULL, /* sym_get_probes */ + &psym_functions +}; + +initialize_file_ftype _initialize_somread; + +void +_initialize_somread (void) +{ + add_symtab_fns (&som_sym_fns); +} diff --git a/contrib/gdb-7/gdb/source.c b/contrib/gdb-7/gdb/source.c index 909f2523b7..a34a78ed14 100644 --- a/contrib/gdb-7/gdb/source.c +++ b/contrib/gdb-7/gdb/source.c @@ -1,5 +1,5 @@ /* List lines of source files for GDB, the GNU debugger. - Copyright (C) 1986-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -109,6 +109,27 @@ show_lines_to_list (struct ui_file *file, int from_tty, value); } +/* Possible values of 'set filename-display'. */ +static const char filename_display_basename[] = "basename"; +static const char filename_display_relative[] = "relative"; +static const char filename_display_absolute[] = "absolute"; + +static const char *const filename_display_kind_names[] = { + filename_display_basename, + filename_display_relative, + filename_display_absolute, + NULL +}; + +static const char *filename_display_string = filename_display_relative; + +static void +show_filename_display_string (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Filenames are displayed as \"%s\".\n"), value); +} + /* Line number of last line printed. Default for various commands. current_source_line is usually, but not always, the same as this. */ @@ -243,7 +264,8 @@ select_source_symtab (struct symtab *s) if one exists. */ if (lookup_symbol (main_name (), 0, VAR_DOMAIN, 0)) { - sals = decode_line_spec (main_name (), DECODE_LINE_FUNFIRSTLINE); + sals = decode_line_with_current_source (main_name (), + DECODE_LINE_FUNFIRSTLINE); sal = sals.sals[0]; xfree (sals.sals); current_source_pspace = sal.pspace; @@ -383,14 +405,14 @@ init_source_path (void) { char buf[20]; - sprintf (buf, "$cdir%c$cwd", DIRNAME_SEPARATOR); + xsnprintf (buf, sizeof (buf), "$cdir%c$cwd", DIRNAME_SEPARATOR); source_path = xstrdup (buf); forget_cached_source_info (); } /* Add zero or more directories to the front of the source path. */ -void +static void directory_command (char *dirname, int from_tty) { dont_repeat (); @@ -440,62 +462,40 @@ add_path (char *dirname, char **which_path, int parse_separators) { char *old = *which_path; int prefix = 0; - char **argv = NULL; - char *arg; - int argv_index = 0; + VEC (char_ptr) *dir_vec = NULL; + struct cleanup *back_to; + int ix; + char *name; if (dirname == 0) return; if (parse_separators) { + char **argv, **argvp; + /* This will properly parse the space and tab separators - and any quotes that may exist. DIRNAME_SEPARATOR will - be dealt with later. */ + and any quotes that may exist. */ argv = gdb_buildargv (dirname); - make_cleanup_freeargv (argv); - arg = argv[0]; + for (argvp = argv; *argvp; argvp++) + dirnames_to_char_ptr_vec_append (&dir_vec, *argvp); + + freeargv (argv); } else - { - arg = xstrdup (dirname); - make_cleanup (xfree, arg); - } + VEC_safe_push (char_ptr, dir_vec, xstrdup (dirname)); + back_to = make_cleanup_free_char_ptr_vec (dir_vec); - do + for (ix = 0; VEC_iterate (char_ptr, dir_vec, ix, name); ++ix) { - char *name = arg; char *p; struct stat st; - { - char *separator = NULL; - - /* Spaces and tabs will have been removed by buildargv(). - The directories will there be split into a list but - each entry may still contain DIRNAME_SEPARATOR. */ - if (parse_separators) - separator = strchr (name, DIRNAME_SEPARATOR); - - if (separator == 0) - p = arg = name + strlen (name); - else - { - p = separator; - arg = p + 1; - while (*arg == DIRNAME_SEPARATOR) - ++arg; - } - - /* If there are no more directories in this argument then start - on the next argument next time round the loop (if any). */ - if (*arg == '\0') - arg = parse_separators ? argv[++argv_index] : NULL; - } - - /* name is the start of the directory. - p is the separator (or null) following the end. */ + /* Spaces and tabs will have been removed by buildargv(). + NAME is the start of the directory. + P is the '\0' following the end. */ + p = name + strlen (name); while (!(IS_DIR_SEPARATOR (*name) && p <= name + 1) /* "/" */ #ifdef HAVE_DOS_BASED_FILE_SYSTEM @@ -573,65 +573,54 @@ add_path (char *dirname, char **which_path, int parse_separators) append: { unsigned int len = strlen (name); + char tinybuf[2]; p = *which_path; - while (1) + /* FIXME: we should use realpath() or its work-alike + before comparing. Then all the code above which + removes excess slashes and dots could simply go away. */ + if (!filename_cmp (p, name)) { - /* FIXME: we should use realpath() or its work-alike - before comparing. Then all the code above which - removes excess slashes and dots could simply go away. */ - if (!filename_ncmp (p, name, len) - && (p[len] == '\0' || p[len] == DIRNAME_SEPARATOR)) - { - /* Found it in the search path, remove old copy. */ - if (p > *which_path) - p--; /* Back over leading separator. */ - if (prefix > p - *which_path) - goto skip_dup; /* Same dir twice in one cmd. */ - strcpy (p, &p[len + 1]); /* Copy from next \0 or : */ - } - p = strchr (p, DIRNAME_SEPARATOR); - if (p != 0) - ++p; - else - break; + /* Found it in the search path, remove old copy. */ + if (p > *which_path) + p--; /* Back over leading separator. */ + if (prefix > p - *which_path) + goto skip_dup; /* Same dir twice in one cmd. */ + memmove (p, &p[len + 1], strlen (&p[len + 1]) + 1); /* Copy from next \0 or : */ } - if (p == 0) - { - char tinybuf[2]; - tinybuf[0] = DIRNAME_SEPARATOR; - tinybuf[1] = '\0'; + tinybuf[0] = DIRNAME_SEPARATOR; + tinybuf[1] = '\0'; - /* If we have already tacked on a name(s) in this command, - be sure they stay on the front as we tack on some - more. */ - if (prefix) - { - char *temp, c; - - c = old[prefix]; - old[prefix] = '\0'; - temp = concat (old, tinybuf, name, (char *)NULL); - old[prefix] = c; - *which_path = concat (temp, "", &old[prefix], (char *) NULL); - prefix = strlen (temp); - xfree (temp); - } - else - { - *which_path = concat (name, (old[0] ? tinybuf : old), - old, (char *)NULL); - prefix = strlen (name); - } - xfree (old); - old = *which_path; + /* If we have already tacked on a name(s) in this command, + be sure they stay on the front as we tack on some + more. */ + if (prefix) + { + char *temp, c; + + c = old[prefix]; + old[prefix] = '\0'; + temp = concat (old, tinybuf, name, (char *)NULL); + old[prefix] = c; + *which_path = concat (temp, "", &old[prefix], (char *) NULL); + prefix = strlen (temp); + xfree (temp); } + else + { + *which_path = concat (name, (old[0] ? tinybuf : old), + old, (char *)NULL); + prefix = strlen (name); + } + xfree (old); + old = *which_path; } skip_dup: ; } - while (arg != NULL); + + do_cleanups (back_to); } @@ -701,6 +690,11 @@ is_regular_file (const char *name) and the file, sigh! Emacs gets confuzzed by this when we print the source file name!!! + If OPTS does not have OPF_DISABLE_REALPATH set return FILENAME_OPENED + resolved by gdb_realpath. Even with OPF_DISABLE_REALPATH this function + still returns filename starting with "/". If FILENAME_OPENED is NULL + this option has no effect. + If a file is found, return the descriptor. Otherwise, return -1, with errno set for the last name we tried to open. */ @@ -712,10 +706,11 @@ openp (const char *path, int opts, const char *string, { int fd; char *filename; - const char *p; - const char *p1; - int len; int alloclen; + VEC (char_ptr) *dir_vec; + struct cleanup *back_to; + int ix; + char *dir; /* The open syscall MODE parameter is not specified. */ gdb_assert ((mode & O_CREAT) == 0); @@ -778,16 +773,15 @@ openp (const char *path, int opts, const char *string, alloclen = strlen (path) + strlen (string) + 2; filename = alloca (alloclen); fd = -1; - for (p = path; p; p = p1 ? p1 + 1 : 0) + + dir_vec = dirnames_to_char_ptr_vec (path); + back_to = make_cleanup_free_char_ptr_vec (dir_vec); + + for (ix = 0; VEC_iterate (char_ptr, dir_vec, ix, dir); ++ix) { - p1 = strchr (p, DIRNAME_SEPARATOR); - if (p1) - len = p1 - p; - else - len = strlen (p); + size_t len = strlen (dir); - if (len == 4 && p[0] == '$' && p[1] == 'c' - && p[2] == 'w' && p[3] == 'd') + if (strcmp (dir, "$cwd") == 0) { /* Name is $cwd -- insert current directory name instead. */ int newlen; @@ -802,11 +796,29 @@ openp (const char *path, int opts, const char *string, } strcpy (filename, current_directory); } + else if (strchr(dir, '~')) + { + /* See whether we need to expand the tilde. */ + int newlen; + char *tilde_expanded; + + tilde_expanded = tilde_expand (dir); + + /* First, realloc the filename buffer if too short. */ + len = strlen (tilde_expanded); + newlen = len + strlen (string) + 2; + if (newlen > alloclen) + { + alloclen = newlen; + filename = alloca (alloclen); + } + strcpy (filename, tilde_expanded); + xfree (tilde_expanded); + } else { /* Normal file name in path -- just use it. */ - strncpy (filename, p, len); - filename[len] = 0; + strcpy (filename, dir); /* Don't search $cdir. It's also a magic path like $cwd, but we don't have enough information to expand it. The user *could* @@ -815,7 +827,7 @@ openp (const char *path, int opts, const char *string, contexts. If the user really has '$cdir' one can use './$cdir'. We can get $cdir when loading scripts. When loading source files $cdir must have already been expanded to the correct value. */ - if (strcmp (filename, "$cdir") == 0) + if (strcmp (dir, "$cdir") == 0) continue; } @@ -834,29 +846,35 @@ openp (const char *path, int opts, const char *string, } } + do_cleanups (back_to); + done: if (filename_opened) { - /* If a file was opened, canonicalize its filename. Use xfullpath - rather than gdb_realpath to avoid resolving the basename part - of filenames when the associated file is a symbolic link. This - fixes a potential inconsistency between the filenames known to - GDB and the filenames it prints in the annotations. */ + /* If a file was opened, canonicalize its filename. */ if (fd < 0) *filename_opened = NULL; - else if (IS_ABSOLUTE_PATH (filename)) - *filename_opened = xfullpath (filename); else { - /* Beware the // my son, the Emacs barfs, the botch that catch... */ + char *(*realpath_fptr) (const char *); + + realpath_fptr = ((opts & OPF_DISABLE_REALPATH) != 0 + ? xstrdup : gdb_realpath); + + if (IS_ABSOLUTE_PATH (filename)) + *filename_opened = realpath_fptr (filename); + else + { + /* Beware the // my son, the Emacs barfs, the botch that catch... */ - char *f = concat (current_directory, - IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]) - ? "" : SLASH_STRING, - filename, (char *)NULL); + char *f = concat (current_directory, + IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]) + ? "" : SLASH_STRING, + filename, (char *)NULL); - *filename_opened = xfullpath (f); - xfree (f); + *filename_opened = realpath_fptr (f); + xfree (f); + } } } @@ -949,7 +967,7 @@ get_substitute_path_rule (const char *path) Return NULL if no substitution rule was specified by the user, or if no rule applied to the given PATH. */ -static char * +char * rewrite_source_path (const char *path) { const struct substitute_path_rule *rule = get_substitute_path_rule (path); @@ -971,26 +989,6 @@ rewrite_source_path (const char *path) return new_path; } -/* This function is capable of finding the absolute path to a - source file, and opening it, provided you give it a FILENAME. Both the - DIRNAME and FULLNAME are only added suggestions on where to find the file. - - FILENAME should be the filename to open. - DIRNAME is the compilation directory of a particular source file. - Only some debug formats provide this info. - FULLNAME can be the last known absolute path to the file in question. - Space for the path must have been malloc'd. If a path substitution - is applied we free the old value and set a new one. - - On Success - A valid file descriptor is returned (the return value is positive). - FULLNAME is set to the absolute path to the file just opened. - The caller is responsible for freeing FULLNAME. - - On Failure - An invalid file descriptor is returned (the return value is negative). - FULLNAME is set to NULL. */ - int find_and_open_source (const char *filename, const char *dirname, @@ -1017,7 +1015,14 @@ find_and_open_source (const char *filename, result = open (*fullname, OPEN_MODE); if (result >= 0) - return result; + { + char *lpath = gdb_realpath (*fullname); + + xfree (*fullname); + *fullname = lpath; + return result; + } + /* Didn't work -- free old one, try again. */ xfree (*fullname); *fullname = NULL; @@ -1098,35 +1103,62 @@ open_source_file (struct symtab *s) /* Finds the fullname that a symtab represents. - If this functions finds the fullname, it will save it in s->fullname - and it will also return the value. + This functions finds the fullname and saves it in s->fullname. + It will also return the value. If this function fails to find the file that this symtab represents, - NULL will be returned and s->fullname will be set to NULL. */ + the expected fullname is used. Therefore the files does not have to + exist. */ -char * +const char * symtab_to_fullname (struct symtab *s) { - int r; - - if (!s) - return NULL; - /* Use cached copy if we have it. We rely on forget_cached_source_info being called appropriately to handle cases like the file being moved. */ - if (s->fullname) - return s->fullname; + if (s->fullname == NULL) + { + int fd = find_and_open_source (s->filename, s->dirname, &s->fullname); - r = find_and_open_source (s->filename, s->dirname, &s->fullname); + if (fd >= 0) + close (fd); + else + { + char *fullname; + struct cleanup *back_to; - if (r >= 0) - { - close (r); - return s->fullname; - } + /* rewrite_source_path would be applied by find_and_open_source, we + should report the pathname where GDB tried to find the file. */ - return NULL; + if (s->dirname == NULL || IS_ABSOLUTE_PATH (s->filename)) + fullname = xstrdup (s->filename); + else + fullname = concat (s->dirname, SLASH_STRING, s->filename, NULL); + + back_to = make_cleanup (xfree, fullname); + s->fullname = rewrite_source_path (fullname); + if (s->fullname == NULL) + s->fullname = xstrdup (fullname); + do_cleanups (back_to); + } + } + + return s->fullname; +} + +/* See commentary in source.h. */ + +const char * +symtab_to_filename_for_display (struct symtab *symtab) +{ + if (filename_display_string == filename_display_basename) + return lbasename (symtab->filename); + else if (filename_display_string == filename_display_absolute) + return symtab_to_fullname (symtab); + else if (filename_display_string == filename_display_relative) + return symtab->filename; + else + internal_error (__FILE__, __LINE__, _("invalid filename_display_string")); } /* Create and initialize the table S->line_charpos that records @@ -1148,7 +1180,7 @@ find_source_lines (struct symtab *s, int desc) gdb_assert (s); line_charpos = (int *) xmalloc (lines_allocated * sizeof (int)); if (fstat (desc, &st) < 0) - perror_with_name (s->filename); + perror_with_name (symtab_to_filename_for_display (s)); if (s->objfile && s->objfile->obfd) mtime = s->objfile->mtime; @@ -1173,7 +1205,7 @@ find_source_lines (struct symtab *s, int desc) /* Reassign `size' to result of read for systems where \r\n -> \n. */ size = myread (desc, data, size); if (size < 0) - perror_with_name (s->filename); + perror_with_name (symtab_to_filename_for_display (s)); end = data + size; p = data; line_charpos[0] = 0; @@ -1268,10 +1300,9 @@ identify_source_line (struct symtab *s, int line, int mid_statement, /* Print source lines from the file of symtab S, starting with line number LINE and stopping before line number STOPLINE. */ -static void print_source_lines_base (struct symtab *s, int line, int stopline, - int noerror); static void -print_source_lines_base (struct symtab *s, int line, int stopline, int noerror) +print_source_lines_base (struct symtab *s, int line, int stopline, + enum print_source_lines_flags flags) { int c; int desc; @@ -1299,13 +1330,13 @@ print_source_lines_base (struct symtab *s, int line, int stopline, int noerror) else { desc = last_source_error; - noerror = 1; + flags |= PRINT_SOURCE_LINES_NOERROR; } } else { desc = last_source_error; - noerror = 1; + flags |= PRINT_SOURCE_LINES_NOERROR; noprint = 1; } @@ -1313,17 +1344,43 @@ print_source_lines_base (struct symtab *s, int line, int stopline, int noerror) { last_source_error = desc; - if (!noerror) + if (!(flags & PRINT_SOURCE_LINES_NOERROR)) { - char *name = alloca (strlen (s->filename) + 100); - sprintf (name, "%d\t%s", line, s->filename); + const char *filename = symtab_to_filename_for_display (s); + int len = strlen (filename) + 100; + char *name = alloca (len); + + xsnprintf (name, len, "%d\t%s", line, filename); print_sys_errmsg (name, errno); } else { ui_out_field_int (uiout, "line", line); ui_out_text (uiout, "\tin "); - ui_out_field_string (uiout, "file", s->filename); + + /* CLI expects only the "file" field. TUI expects only the + "fullname" field (and TUI does break if "file" is printed). + MI expects both fields. ui_source_list is set only for CLI, + not for TUI. */ + if (ui_out_is_mi_like_p (uiout) + || ui_out_test_flags (uiout, ui_source_list)) + ui_out_field_string (uiout, "file", + symtab_to_filename_for_display (s)); + if (ui_out_is_mi_like_p (uiout) + || !ui_out_test_flags (uiout, ui_source_list)) + { + const char *s_fullname = symtab_to_fullname (s); + char *local_fullname; + + /* ui_out_field_string may free S_FULLNAME by calling + open_source_file for it again. See e.g., + tui_field_string->tui_show_source. */ + local_fullname = alloca (strlen (s_fullname) + 1); + strcpy (local_fullname, s_fullname); + + ui_out_field_string (uiout, "fullname", local_fullname); + } + ui_out_text (uiout, "\n"); } @@ -1339,13 +1396,13 @@ print_source_lines_base (struct symtab *s, int line, int stopline, int noerror) { close (desc); error (_("Line number %d out of range; %s has %d lines."), - line, s->filename, s->nlines); + line, symtab_to_filename_for_display (s), s->nlines); } if (lseek (desc, s->line_charpos[line - 1], 0) < 0) { close (desc); - perror_with_name (s->filename); + perror_with_name (symtab_to_filename_for_display (s)); } stream = fdopen (desc, FDOPEN_MODE); @@ -1360,13 +1417,18 @@ print_source_lines_base (struct symtab *s, int line, int stopline, int noerror) if (c == EOF) break; last_line_listed = current_source_line; - sprintf (buf, "%d\t", current_source_line++); + if (flags & PRINT_SOURCE_LINES_FILENAME) + { + ui_out_text (uiout, symtab_to_filename_for_display (s)); + ui_out_text (uiout, ":"); + } + xsnprintf (buf, sizeof (buf), "%d\t", current_source_line++); ui_out_text (uiout, buf); do { if (c < 040 && c != '\t' && c != '\n' && c != '\r') { - sprintf (buf, "^%c", c + 0100); + xsnprintf (buf, sizeof (buf), "^%c", c + 0100); ui_out_text (uiout, buf); } else if (c == 0177) @@ -1383,7 +1445,7 @@ print_source_lines_base (struct symtab *s, int line, int stopline, int noerror) } else { - sprintf (buf, "%c", c); + xsnprintf (buf, sizeof (buf), "%c", c); ui_out_text (uiout, buf); } } @@ -1399,9 +1461,10 @@ print_source_lines_base (struct symtab *s, int line, int stopline, int noerror) window otherwise it is simply printed. */ void -print_source_lines (struct symtab *s, int line, int stopline, int noerror) +print_source_lines (struct symtab *s, int line, int stopline, + enum print_source_lines_flags flags) { - print_source_lines_base (s, line, stopline, noerror); + print_source_lines_base (s, line, stopline, flags); } /* Print info on range of pc's in a specified line. */ @@ -1429,7 +1492,7 @@ line_info (char *arg, int from_tty) } else { - sals = decode_line_spec_1 (arg, DECODE_LINE_LIST_MODE); + sals = decode_line_with_last_displayed (arg, DECODE_LINE_LIST_MODE); dont_repeat (); } @@ -1470,7 +1533,8 @@ line_info (char *arg, int from_tty) if (start_pc == end_pc) { printf_filtered ("Line %d of \"%s\"", - sal.line, sal.symtab->filename); + sal.line, + symtab_to_filename_for_display (sal.symtab)); wrap_here (" "); printf_filtered (" is at address "); print_address (gdbarch, start_pc, gdb_stdout); @@ -1480,7 +1544,8 @@ line_info (char *arg, int from_tty) else { printf_filtered ("Line %d of \"%s\"", - sal.line, sal.symtab->filename); + sal.line, + symtab_to_filename_for_display (sal.symtab)); wrap_here (" "); printf_filtered (" starts at address "); print_address (gdbarch, start_pc, gdb_stdout); @@ -1506,7 +1571,7 @@ line_info (char *arg, int from_tty) which the user would want to see? If we have debugging symbols and no line numbers? */ printf_filtered (_("Line number %d is out of range for \"%s\".\n"), - sal.line, sal.symtab->filename); + sal.line, symtab_to_filename_for_display (sal.symtab)); } do_cleanups (cleanups); } @@ -1534,7 +1599,7 @@ forward_search_command (char *regex, int from_tty) desc = open_source_file (current_source_symtab); if (desc < 0) - perror_with_name (current_source_symtab->filename); + perror_with_name (symtab_to_filename_for_display (current_source_symtab)); cleanups = make_cleanup_close (desc); if (current_source_symtab->line_charpos == 0) @@ -1544,7 +1609,7 @@ forward_search_command (char *regex, int from_tty) error (_("Expression not found")); if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0) - perror_with_name (current_source_symtab->filename); + perror_with_name (symtab_to_filename_for_display (current_source_symtab)); discard_cleanups (cleanups); stream = fdopen (desc, FDOPEN_MODE); @@ -1623,7 +1688,7 @@ reverse_search_command (char *regex, int from_tty) desc = open_source_file (current_source_symtab); if (desc < 0) - perror_with_name (current_source_symtab->filename); + perror_with_name (symtab_to_filename_for_display (current_source_symtab)); cleanups = make_cleanup_close (desc); if (current_source_symtab->line_charpos == 0) @@ -1633,7 +1698,7 @@ reverse_search_command (char *regex, int from_tty) error (_("Expression not found")); if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0) - perror_with_name (current_source_symtab->filename); + perror_with_name (symtab_to_filename_for_display (current_source_symtab)); discard_cleanups (cleanups); stream = fdopen (desc, FDOPEN_MODE); @@ -1676,8 +1741,11 @@ reverse_search_command (char *regex, int from_tty) line--; if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0) { + const char *filename; + do_cleanups (cleanups); - perror_with_name (current_source_symtab->filename); + filename = symtab_to_filename_for_display (current_source_symtab); + perror_with_name (filename); } } @@ -1976,6 +2044,7 @@ The address is also stored as the value of \"$_\".")); Search for regular expression (see regex(3)) from last line listed.\n\ The matching line number is also stored as the value of \"$_\".")); add_com_alias ("search", "forward-search", class_files, 0); + add_com_alias ("fo", "forward-search", class_files, 1); add_com ("reverse-search", class_files, reverse_search_command, _("\ Search backward for regular expression (see regex(3)) from last line listed.\n\ @@ -2017,4 +2086,19 @@ Usage: show substitute-path [FROM]\n\ Print the rule for substituting FROM in source file names. If FROM\n\ is not specified, print all substitution rules."), &showlist); + + add_setshow_enum_cmd ("filename-display", class_files, + filename_display_kind_names, + &filename_display_string, _("\ +Set how to display filenames."), _("\ +Show how to display filenames."), _("\ +filename-display can be:\n\ + basename - display only basename of a filename\n\ + relative - display a filename relative to the compilation directory\n\ + absolute - display an absolute filename\n\ +By default, relative filenames are displayed."), + NULL, + show_filename_display_string, + &setlist, &showlist); + } diff --git a/contrib/gdb-7/gdb/source.h b/contrib/gdb-7/gdb/source.h index 3ee8e532bb..33cad09967 100644 --- a/contrib/gdb-7/gdb/source.h +++ b/contrib/gdb-7/gdb/source.h @@ -1,5 +1,5 @@ /* List lines of source files for GDB, the GNU debugger. - Copyright (C) 1999, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1999-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -21,11 +21,40 @@ struct symtab; +/* This function is capable of finding the absolute path to a + source file, and opening it, provided you give it a FILENAME. Both the + DIRNAME and FULLNAME are only added suggestions on where to find the file. + + FILENAME should be the filename to open. + DIRNAME is the compilation directory of a particular source file. + Only some debug formats provide this info. + FULLNAME can be the last known absolute path to the file in question. + Space for the path must have been malloc'd. If a path substitution + is applied we free the old value and set a new one. + + On Success + A valid file descriptor is returned (the return value is positive). + FULLNAME is set to the absolute path to the file just opened. + The caller is responsible for freeing FULLNAME. + + On Failure + An invalid file descriptor is returned (the return value is negative). + FULLNAME is set to NULL. */ +extern int find_and_open_source (const char *filename, + const char *dirname, + char **fullname); + /* Open a source file given a symtab S. Returns a file descriptor or negative number for error. */ extern int open_source_file (struct symtab *s); -extern char* symtab_to_fullname (struct symtab *s); +extern char *rewrite_source_path (const char *path); + +extern const char *symtab_to_fullname (struct symtab *s); + +/* Returns filename without the compile directory part, basename or absolute + filename. It depends on 'set filename-display' value. */ +extern const char *symtab_to_filename_for_display (struct symtab *symtab); /* Create and initialize the table S->line_charpos that records the positions of the lines in the source file, which is assumed to be diff --git a/contrib/gdb-7/gdb/ravenscar-sparc-thread.c b/contrib/gdb-7/gdb/sparc-ravenscar-thread.c similarity index 85% rename from contrib/gdb-7/gdb/ravenscar-sparc-thread.c rename to contrib/gdb-7/gdb/sparc-ravenscar-thread.c index 93af256b51..43a20690da 100644 --- a/contrib/gdb-7/gdb/ravenscar-sparc-thread.c +++ b/contrib/gdb-7/gdb/sparc-ravenscar-thread.c @@ -1,6 +1,6 @@ /* Ravenscar SPARC target support. - Copyright 2004, 2010-2012 Free Software Foundation, Inc. + Copyright (C) 2004-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -23,14 +23,13 @@ #include "sparc-tdep.h" #include "inferior.h" #include "ravenscar-thread.h" +#include "sparc-ravenscar-thread.h" -static struct ravenscar_arch_ops ravenscar_sparc_ops; - -static void ravenscar_sparc_fetch_registers (struct regcache *regcache, +static void sparc_ravenscar_fetch_registers (struct regcache *regcache, int regnum); -static void ravenscar_sparc_store_registers (struct regcache *regcache, +static void sparc_ravenscar_store_registers (struct regcache *regcache, int regnum); -static void ravenscar_sparc_prepare_to_store (struct regcache *regcache); +static void sparc_ravenscar_prepare_to_store (struct regcache *regcache); /* Register offsets from a referenced address (exempli gratia the Thread_Descriptor). The referenced address depends on the register @@ -102,7 +101,7 @@ register_in_thread_descriptor_p (int regnum) thread. */ static void -ravenscar_sparc_fetch_registers (struct regcache *regcache, int regnum) +sparc_ravenscar_fetch_registers (struct regcache *regcache, int regnum) { struct gdbarch *gdbarch = get_regcache_arch (regcache); const int sp_regnum = gdbarch_sp_regnum (gdbarch); @@ -112,12 +111,16 @@ ravenscar_sparc_fetch_registers (struct regcache *regcache, int regnum) CORE_ADDR thread_descriptor_address; ULONGEST stack_address; + /* The tid is the thread_id field, which is a pointer to the thread. */ thread_descriptor_address = (CORE_ADDR) ptid_get_tid (inferior_ptid); + + /* Read the saved SP in the context buffer. */ current_address = thread_descriptor_address + sparc_register_offsets [sp_regnum]; supply_register_at_address (regcache, sp_regnum, current_address); regcache_cooked_read_unsigned (regcache, sp_regnum, &stack_address); + /* Read registers. */ for (current_regnum = 0; current_regnum < num_regs; current_regnum ++) { if (register_in_thread_descriptor_p (current_regnum)) @@ -141,7 +144,7 @@ ravenscar_sparc_fetch_registers (struct regcache *regcache, int regnum) thread. */ static void -ravenscar_sparc_prepare_to_store (struct regcache *regcache) +sparc_ravenscar_prepare_to_store (struct regcache *regcache) { /* Nothing to do. */ } @@ -150,7 +153,7 @@ ravenscar_sparc_prepare_to_store (struct regcache *regcache) thread. */ static void -ravenscar_sparc_store_registers (struct regcache *regcache, int regnum) +sparc_ravenscar_store_registers (struct regcache *regcache, int regnum) { struct gdbarch *gdbarch = get_regcache_arch (regcache); int buf_size = register_size (gdbarch, regnum); @@ -175,11 +178,17 @@ ravenscar_sparc_store_registers (struct regcache *regcache, int regnum) buf_size); } +static struct ravenscar_arch_ops sparc_ravenscar_ops = +{ + sparc_ravenscar_fetch_registers, + sparc_ravenscar_store_registers, + sparc_ravenscar_prepare_to_store +}; + +/* Register ravenscar_arch_ops in GDBARCH. */ + void -_initialize_ravenscar_sparc (void) +register_sparc_ravenscar_ops (struct gdbarch *gdbarch) { - ravenscar_sparc_ops.to_fetch_registers = ravenscar_sparc_fetch_registers; - ravenscar_sparc_ops.to_store_registers = ravenscar_sparc_store_registers; - ravenscar_sparc_ops.to_prepare_to_store = ravenscar_sparc_prepare_to_store; - ravenscar_register_arch_ops (&ravenscar_sparc_ops); + set_gdbarch_ravenscar_ops (gdbarch, &sparc_ravenscar_ops); } diff --git a/contrib/gdb-7/gdb/gdb_vfork.h b/contrib/gdb-7/gdb/sparc-ravenscar-thread.h similarity index 73% copy from contrib/gdb-7/gdb/gdb_vfork.h copy to contrib/gdb-7/gdb/sparc-ravenscar-thread.h index 736519db50..bac41523a3 100644 --- a/contrib/gdb-7/gdb/gdb_vfork.h +++ b/contrib/gdb-7/gdb/sparc-ravenscar-thread.h @@ -1,5 +1,6 @@ -/* GDB-friendly replacement for . - Copyright (C) 2001, 2007-2012 Free Software Foundation, Inc. +/* Ravenscar SPARC target support. + + Copyright (C) 2012-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -16,11 +17,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef GDB_VFORK_H -#define GDB_VFORK_H +#ifndef SPARC_RAVENSCAR_THREAD_H +#define SPARC_RAVENSCAR_THREAD_H -#if HAVE_VFORK_H -#include -#endif +struct gdbarch; -#endif /* GDB_VFORK_H */ +extern void register_sparc_ravenscar_ops (struct gdbarch *gdbarch); +#endif diff --git a/contrib/gdb-7/gdb/stabsread.c b/contrib/gdb-7/gdb/stabsread.c index 865bac8530..a38ead1552 100644 --- a/contrib/gdb-7/gdb/stabsread.c +++ b/contrib/gdb-7/gdb/stabsread.c @@ -1,6 +1,6 @@ /* Support routines for decoding "stabs" debugging information format. - Copyright (C) 1986-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -98,7 +98,7 @@ static void patch_block_stabs (struct pending *, struct pending_stabs *, struct objfile *); -static void fix_common_block (struct symbol *, int); +static void fix_common_block (struct symbol *, CORE_ADDR); static int read_type_number (char **, int *); @@ -387,8 +387,8 @@ patch_block_stabs (struct pending *symbols, struct pending_stabs *stabs, SYMBOL_DOMAIN (sym) = VAR_DOMAIN; SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; SYMBOL_SET_LINKAGE_NAME - (sym, obsavestring (name, pp - name, - &objfile->objfile_obstack)); + (sym, obstack_copy0 (&objfile->objfile_obstack, + name, pp - name)); pp += 2; if (*(pp - 1) == 'F' || *(pp - 1) == 'f') { @@ -1173,7 +1173,7 @@ define_symbol (CORE_ADDR valu, char *string, int desc, int type, NULL, objfile); if (msym != NULL) { - char *new_name = gdbarch_static_transform_name + const char *new_name = gdbarch_static_transform_name (gdbarch, SYMBOL_LINKAGE_NAME (sym)); SYMBOL_SET_LINKAGE_NAME (sym, new_name); @@ -1367,7 +1367,7 @@ define_symbol (CORE_ADDR valu, char *string, int desc, int type, NULL, objfile); if (msym != NULL) { - char *new_name = gdbarch_static_transform_name + const char *new_name = gdbarch_static_transform_name (gdbarch, SYMBOL_LINKAGE_NAME (sym)); SYMBOL_SET_LINKAGE_NAME (sym, new_name); @@ -1632,8 +1632,8 @@ again: new_name = cp_canonicalize_string (name); if (new_name != NULL) { - type_name = obsavestring (new_name, strlen (new_name), - &objfile->objfile_obstack); + type_name = obstack_copy0 (&objfile->objfile_obstack, + new_name, strlen (new_name)); xfree (new_name); } } @@ -2024,11 +2024,9 @@ again: make_vector_type (type); break; - case 'S': /* Set or bitstring type */ + case 'S': /* Set type */ type1 = read_type (pp, objfile); type = create_set_type ((struct type *) NULL, type1); - if (is_string) - TYPE_CODE (type) = TYPE_CODE_BITSTRING; if (typenums[0] != -1) *dbx_lookup_type (typenums, objfile) = type; break; @@ -2232,10 +2230,11 @@ rs6000_builtin_type (int typenum, struct objfile *objfile) /* This page contains subroutines of read_type. */ -/* Replace *OLD_NAME with the method name portion of PHYSNAME. */ +/* Wrapper around method_name_from_physname to flag a complaint + if there is an error. */ -static void -update_method_name_from_physname (char **old_name, const char *physname) +static char * +stabs_method_name_from_physname (const char *physname) { char *method_name; @@ -2245,16 +2244,10 @@ update_method_name_from_physname (char **old_name, const char *physname) { complaint (&symfile_complaints, _("Method has bad physname %s\n"), physname); - return; + return NULL; } - if (strcmp (*old_name, method_name) != 0) - { - xfree (*old_name); - *old_name = method_name; - } - else - xfree (method_name); + return method_name; } /* Read member function stabs info for C++ classes. The form of each member @@ -2278,10 +2271,6 @@ read_member_functions (struct field_info *fip, char **pp, struct type *type, { int nfn_fields = 0; int length = 0; - /* Total number of member functions defined in this class. If the class - defines two `f' functions, and one `g' function, then this will have - the value 3. */ - int total_length = 0; int i; struct next_fnfield { @@ -2681,7 +2670,6 @@ read_member_functions (struct field_info *fip, char **pp, struct type *type, destr_fnlist->next = fip->fnlist; fip->fnlist = destr_fnlist; nfn_fields++; - total_length += has_destructor; length -= has_destructor; } else if (is_v3) @@ -2692,14 +2680,24 @@ read_member_functions (struct field_info *fip, char **pp, struct type *type, - in -gstabs instead of -gstabs+ - or for static methods, which are output as a function type instead of a method type. */ + char *new_method_name = + stabs_method_name_from_physname (sublist->fn_field.physname); - update_method_name_from_physname (&new_fnlist->fn_fieldlist.name, - sublist->fn_field.physname); + if (new_method_name != NULL + && strcmp (new_method_name, + new_fnlist->fn_fieldlist.name) != 0) + { + new_fnlist->fn_fieldlist.name = new_method_name; + xfree (main_fn_name); + } + else + xfree (new_method_name); } else if (has_destructor && new_fnlist->fn_fieldlist.name[0] != '~') { new_fnlist->fn_fieldlist.name = - concat ("~", main_fn_name, (char *)NULL); + obconcat (&objfile->objfile_obstack, + "~", main_fn_name, (char *)NULL); xfree (main_fn_name); } else if (!has_stub) @@ -2714,8 +2712,9 @@ read_member_functions (struct field_info *fip, char **pp, struct type *type, dem_opname, 0); if (ret) new_fnlist->fn_fieldlist.name - = obsavestring (dem_opname, strlen (dem_opname), - &objfile->objfile_obstack); + = obstack_copy0 (&objfile->objfile_obstack, + dem_opname, strlen (dem_opname)); + xfree (main_fn_name); } new_fnlist->fn_fieldlist.fn_fields = (struct fn_field *) @@ -2732,7 +2731,6 @@ read_member_functions (struct field_info *fip, char **pp, struct type *type, new_fnlist->next = fip->fnlist; fip->fnlist = new_fnlist; nfn_fields++; - total_length += length; } } @@ -2744,7 +2742,6 @@ read_member_functions (struct field_info *fip, char **pp, struct type *type, memset (TYPE_FN_FIELDLISTS (type), 0, sizeof (struct fn_fieldlist) * nfn_fields); TYPE_NFN_FIELDS (type) = nfn_fields; - TYPE_NFN_FIELDS_TOTAL (type) = total_length; } return 1; @@ -2760,7 +2757,7 @@ read_cpp_abbrev (struct field_info *fip, char **pp, struct type *type, struct objfile *objfile) { char *p; - char *name; + const char *name; char cpp_abbrev; struct type *context; @@ -2831,8 +2828,8 @@ read_cpp_abbrev (struct field_info *fip, char **pp, struct type *type, { int nbits; - FIELD_BITPOS (fip->list->field) = read_huge_number (pp, ';', &nbits, - 0); + SET_FIELD_BITPOS (fip->list->field, + read_huge_number (pp, ';', &nbits, 0)); if (nbits != 0) return 0; } @@ -2858,7 +2855,7 @@ read_one_struct_field (struct field_info *fip, char **pp, char *p, struct gdbarch *gdbarch = get_objfile_arch (objfile); fip->list->field.name = - obsavestring (*pp, p - *pp, &objfile->objfile_obstack); + obstack_copy0 (&objfile->objfile_obstack, *pp, p - *pp); *pp = p + 1; /* This means we have a visibility for a field coming. */ @@ -2908,7 +2905,8 @@ read_one_struct_field (struct field_info *fip, char **pp, char *p, { int nbits; - FIELD_BITPOS (fip->list->field) = read_huge_number (pp, ',', &nbits, 0); + SET_FIELD_BITPOS (fip->list->field, + read_huge_number (pp, ',', &nbits, 0)); if (nbits != 0) { stabs_general_complaint ("bad structure-type format"); @@ -3188,7 +3186,7 @@ read_baseclasses (struct field_info *fip, char **pp, struct type *type, corresponding to this baseclass. Always zero in the absence of multiple inheritance. */ - FIELD_BITPOS (new->field) = read_huge_number (pp, ',', &nbits, 0); + SET_FIELD_BITPOS (new->field, read_huge_number (pp, ',', &nbits, 0)); if (nbits != 0) return 0; } @@ -3273,7 +3271,7 @@ read_tilde_fields (struct field_info *fip, char **pp, struct type *type, i >= TYPE_N_BASECLASSES (t); --i) { - char *name = TYPE_FIELD_NAME (t, i); + const char *name = TYPE_FIELD_NAME (t, i); if (!strncmp (name, vptr_name, sizeof (vptr_name) - 2) && is_cplus_marker (name[sizeof (vptr_name) - 2])) @@ -3413,8 +3411,8 @@ attach_fields_to_type (struct field_info *fip, struct type *type, static void complain_about_struct_wipeout (struct type *type) { - char *name = ""; - char *kind = ""; + const char *name = ""; + const char *kind = ""; if (TYPE_TAG_NAME (type)) { @@ -3676,7 +3674,7 @@ read_enum_type (char **pp, struct type *type, p = *pp; while (*p != ':') p++; - name = obsavestring (*pp, p - *pp, &objfile->objfile_obstack); + name = obstack_copy0 (&objfile->objfile_obstack, *pp, p - *pp); *pp = p + 1; n = read_huge_number (pp, ',', &nbits, 0); if (nbits != 0) @@ -3731,7 +3729,7 @@ read_enum_type (char **pp, struct type *type, SYMBOL_TYPE (xsym) = type; TYPE_FIELD_NAME (type, n) = SYMBOL_LINKAGE_NAME (xsym); - TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym); + SET_FIELD_ENUMVAL (TYPE_FIELD (type, n), SYMBOL_VALUE (xsym)); TYPE_FIELD_BITSIZE (type, n) = 0; } if (syms == osyms) @@ -4330,8 +4328,8 @@ common_block_start (char *name, struct objfile *objfile) } common_block = local_symbols; common_block_i = local_symbols ? local_symbols->nsyms : 0; - common_block_name = obsavestring (name, strlen (name), - &objfile->objfile_obstack); + common_block_name = obstack_copy0 (&objfile->objfile_obstack, + name, strlen (name)); } /* Process a N_ECOMM symbol. */ @@ -4398,7 +4396,7 @@ common_block_end (struct objfile *objfile) the common block name). */ static void -fix_common_block (struct symbol *sym, int valu) +fix_common_block (struct symbol *sym, CORE_ADDR valu) { struct pending *next = (struct pending *) SYMBOL_TYPE (sym); @@ -4552,7 +4550,7 @@ cleanup_undefined_types_1 (void) struct pending *ppt; int i; /* Name of the type, without "struct" or "union". */ - char *typename = TYPE_TAG_NAME (*type); + const char *typename = TYPE_TAG_NAME (*type); if (typename == NULL) { @@ -4598,7 +4596,7 @@ cleanup_undefined_types_1 (void) this unit. */ void -cleanup_undefined_types (struct objfile *objfile) +cleanup_undefined_stabs_types (struct objfile *objfile) { cleanup_undefined_types_1 (); cleanup_undefined_types_noname (objfile); diff --git a/contrib/gdb-7/gdb/stabsread.h b/contrib/gdb-7/gdb/stabsread.h index 071552ea1d..9563106501 100644 --- a/contrib/gdb-7/gdb/stabsread.h +++ b/contrib/gdb-7/gdb/stabsread.h @@ -1,6 +1,5 @@ /* Include file for stabs debugging format support functions. - Copyright (C) 1986-1997, 1999-2003, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -129,7 +128,7 @@ EXTERN int n_this_object_header_files; EXTERN int n_allocated_this_object_header_files; -extern void cleanup_undefined_types (struct objfile *); +extern void cleanup_undefined_stabs_types (struct objfile *); extern long read_number (char **, int); @@ -161,8 +160,9 @@ struct stab_section_list /* Functions exported by dbxread.c. These are not in stabsread.c because they are only used by some stabs readers. */ -extern struct partial_symtab *end_psymtab (struct partial_symtab *pst, - char **include_list, +extern struct partial_symtab *end_psymtab (struct objfile *objfile, + struct partial_symtab *pst, + const char **include_list, int num_includes, int capping_symbol_offset, CORE_ADDR capping_text, diff --git a/contrib/gdb-7/gdb/stack.c b/contrib/gdb-7/gdb/stack.c index b15b5fcfa1..ea5a306a39 100644 --- a/contrib/gdb-7/gdb/stack.c +++ b/contrib/gdb-7/gdb/stack.c @@ -1,6 +1,6 @@ /* Print and select stack frames for GDB, the GNU debugger. - Copyright (C) 1986-2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -46,6 +46,7 @@ #include "disasm.h" #include "inline-frame.h" #include "linespec.h" +#include "cli/cli-utils.h" #include "gdb_assert.h" #include @@ -59,7 +60,7 @@ void (*deprecated_selected_frame_level_changed_hook) (int); /* The possible choices of "set print frame-arguments", and the value of this setting. */ -static const char *print_frame_arguments_choices[] = +static const char *const print_frame_arguments_choices[] = {"all", "scalars", "none", NULL}; static const char *print_frame_arguments = "scalars"; @@ -73,7 +74,7 @@ const char print_entry_values_if_needed[] = "if-needed"; const char print_entry_values_both[] = "both"; const char print_entry_values_compact[] = "compact"; const char print_entry_values_default[] = "default"; -static const char *print_entry_values_choices[] = +static const char *const print_entry_values_choices[] = { print_entry_values_no, print_entry_values_only, @@ -210,10 +211,10 @@ print_frame_arg (const struct frame_arg *arg) struct ui_out *uiout = current_uiout; volatile struct gdb_exception except; struct cleanup *old_chain; - struct ui_stream *stb; + struct ui_file *stb; - stb = ui_out_stream_new (uiout); - old_chain = make_cleanup_ui_out_stream_delete (stb); + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); gdb_assert (!arg->val || !arg->error); gdb_assert (arg->entry_kind == print_entry_values_no @@ -224,21 +225,21 @@ print_frame_arg (const struct frame_arg *arg) annotate_arg_begin (); make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - fprintf_symbol_filtered (stb->stream, SYMBOL_PRINT_NAME (arg->sym), + fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (arg->sym), SYMBOL_LANGUAGE (arg->sym), DMGL_PARAMS | DMGL_ANSI); if (arg->entry_kind == print_entry_values_compact) { /* It is OK to provide invalid MI-like stream as with PRINT_ENTRY_VALUE_COMPACT we never use MI. */ - fputs_filtered ("=", stb->stream); + fputs_filtered ("=", stb); - fprintf_symbol_filtered (stb->stream, SYMBOL_PRINT_NAME (arg->sym), + fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (arg->sym), SYMBOL_LANGUAGE (arg->sym), DMGL_PARAMS | DMGL_ANSI); } if (arg->entry_kind == print_entry_values_only || arg->entry_kind == print_entry_values_compact) - fputs_filtered ("@entry", stb->stream); + fputs_filtered ("@entry", stb); ui_out_field_stream (uiout, "name", stb); annotate_arg_name_end (); ui_out_text (uiout, "="); @@ -279,22 +280,43 @@ print_frame_arg (const struct frame_arg *arg) /* True in "summary" mode, false otherwise. */ opts.summary = !strcmp (print_frame_arguments, "scalars"); - common_val_print (arg->val, stb->stream, 2, &opts, language); + common_val_print (arg->val, stb, 2, &opts, language); } } if (except.message) - fprintf_filtered (stb->stream, _(""), + fprintf_filtered (stb, _(""), except.message); } ui_out_field_stream (uiout, "value", stb); - /* Aleo invoke ui_out_tuple_end. */ + /* Also invoke ui_out_tuple_end. */ do_cleanups (old_chain); annotate_arg_end (); } +/* Read in inferior function local SYM at FRAME into ARGP. Caller is + responsible for xfree of ARGP->ERROR. This function never throws an + exception. */ + +void +read_frame_local (struct symbol *sym, struct frame_info *frame, + struct frame_arg *argp) +{ + volatile struct gdb_exception except; + struct value *val = NULL; + + TRY_CATCH (except, RETURN_MASK_ERROR) + { + val = read_var_value (sym, frame); + } + + argp->error = (val == NULL) ? xstrdup (except.message) : NULL; + argp->sym = sym; + argp->val = val; +} + /* Read in inferior function parameter SYM at FRAME into ARGP. Caller is responsible for xfree of ARGP->ERROR. This function never throws an exception. */ @@ -354,14 +376,15 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, if (val && entryval && !ui_out_is_mi_like_p (current_uiout)) { - unsigned len = TYPE_LENGTH (value_type (val)); + struct type *type = value_type (val); if (!value_optimized_out (val) && value_lazy (val)) value_fetch_lazy (val); if (!value_optimized_out (val) && value_lazy (entryval)) value_fetch_lazy (entryval); if (!value_optimized_out (val) - && value_available_contents_eq (val, 0, entryval, 0, len)) + && value_available_contents_eq (val, 0, entryval, 0, + TYPE_LENGTH (type))) { /* Initialize it just to avoid a GCC false warning. */ struct value *val_deref = NULL, *entryval_deref; @@ -373,12 +396,12 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, TRY_CATCH (except, RETURN_MASK_ERROR) { - unsigned len_deref; + struct type *type_deref; val_deref = coerce_ref (val); if (value_lazy (val_deref)) value_fetch_lazy (val_deref); - len_deref = TYPE_LENGTH (value_type (val_deref)); + type_deref = value_type (val_deref); entryval_deref = coerce_ref (entryval); if (value_lazy (entryval_deref)) @@ -389,7 +412,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, if (val != val_deref && value_available_contents_eq (val_deref, 0, entryval_deref, 0, - len_deref)) + TYPE_LENGTH (type_deref))) val_equal = 1; } @@ -499,20 +522,18 @@ print_frame_args (struct symbol *func, struct frame_info *frame, long highest_offset = -1; /* Number of ints of arguments that we have printed so far. */ int args_printed = 0; - struct cleanup *old_chain, *list_chain; - struct ui_stream *stb; + struct cleanup *old_chain; + struct ui_file *stb; /* True if we should print arguments, false otherwise. */ int print_args = strcmp (print_frame_arguments, "none"); - /* True in "summary" mode, false otherwise. */ - int summary = !strcmp (print_frame_arguments, "scalars"); - stb = ui_out_stream_new (uiout); - old_chain = make_cleanup_ui_out_stream_delete (stb); + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); if (func) { struct block *b = SYMBOL_BLOCK_VALUE (func); - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym; ALL_BLOCK_SYMBOLS (b, iter, sym) @@ -909,6 +930,12 @@ set_last_displayed_sal (int valid, struct program_space *pspace, last_displayed_addr = addr; last_displayed_symtab = symtab; last_displayed_line = line; + if (valid && pspace == NULL) + { + clear_last_displayed_sal (); + internal_error (__FILE__, __LINE__, + _("Trying to set NULL pspace.")); + } } /* Forget the last sal we displayed. */ @@ -999,7 +1026,7 @@ get_last_displayed_sal (struct symtab_and_line *sal) corresponding to FRAME. */ void -find_frame_funname (struct frame_info *frame, char **funname, +find_frame_funname (struct frame_info *frame, const char **funname, enum language *funlang, struct symbol **funcp) { struct symbol *func; @@ -1095,9 +1122,9 @@ print_frame (struct frame_info *frame, int print_level, { struct gdbarch *gdbarch = get_frame_arch (frame); struct ui_out *uiout = current_uiout; - char *funname = NULL; + const char *funname = NULL; enum language funlang = language_unknown; - struct ui_stream *stb; + struct ui_file *stb; struct cleanup *old_chain, *list_chain; struct value_print_options opts; struct symbol *func; @@ -1106,8 +1133,8 @@ print_frame (struct frame_info *frame, int print_level, pc_p = get_frame_pc_if_available (frame, &pc); - stb = ui_out_stream_new (uiout); - old_chain = make_cleanup_ui_out_stream_delete (stb); + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); find_frame_funname (frame, &funname, &funlang, &func); @@ -1137,7 +1164,7 @@ print_frame (struct frame_info *frame, int print_level, ui_out_text (uiout, " in "); } annotate_frame_function_name (); - fprintf_symbol_filtered (stb->stream, funname ? funname : "??", + fprintf_symbol_filtered (stb, funname ? funname : "??", funlang, DMGL_ANSI); ui_out_field_stream (uiout, "func", stb); ui_out_wrap_hint (uiout, " "); @@ -1171,19 +1198,21 @@ print_frame (struct frame_info *frame, int print_level, QUIT; } ui_out_text (uiout, ")"); - if (sal.symtab && sal.symtab->filename) + if (sal.symtab) { + const char *filename_display; + + filename_display = symtab_to_filename_for_display (sal.symtab); annotate_frame_source_begin (); ui_out_wrap_hint (uiout, " "); ui_out_text (uiout, " at "); annotate_frame_source_file (); - ui_out_field_string (uiout, "file", sal.symtab->filename); + ui_out_field_string (uiout, "file", filename_display); if (ui_out_is_mi_like_p (uiout)) { const char *fullname = symtab_to_fullname (sal.symtab); - if (fullname != NULL) - ui_out_field_string (uiout, "fullname", fullname); + ui_out_field_string (uiout, "fullname", fullname); } annotate_frame_source_file_end (); ui_out_text (uiout, ":"); @@ -1192,7 +1221,7 @@ print_frame (struct frame_info *frame, int print_level, annotate_frame_source_end (); } - if (pc_p && (!funname || (!sal.symtab || !sal.symtab->filename))) + if (pc_p && (funname == NULL || sal.symtab == NULL)) { #ifdef PC_SOLIB char *lib = PC_SOLIB (get_frame_pc (frame)); @@ -1242,8 +1271,7 @@ parse_frame_specification_1 (const char *frame_exp, const char *message, const char *p; /* Skip leading white space, bail of EOL. */ - while (isspace (*frame_exp)) - frame_exp++; + frame_exp = skip_spaces_const (frame_exp); if (!*frame_exp) break; @@ -1363,7 +1391,7 @@ frame_info (char *addr_exp, int from_tty) struct symtab *s; struct frame_info *calling_frame_info; int numregs; - char *funname = 0; + const char *funname = 0; enum language funlang = language_unknown; const char *pc_regname; int selected_frame_p; @@ -1453,7 +1481,8 @@ frame_info (char *addr_exp, int from_tty) } wrap_here (" "); if (sal.symtab) - printf_filtered (" (%s:%d)", sal.symtab->filename, sal.line); + printf_filtered (" (%s:%d)", symtab_to_filename_for_display (sal.symtab), + sal.line); puts_filtered ("; "); wrap_here (" "); printf_filtered ("saved %s ", pc_regname); @@ -1721,7 +1750,20 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty) the frame->prev field gets set to NULL in that case). */ print_frame_info (fi, 1, LOCATION, 1); if (show_locals) - print_frame_local_vars (fi, 1, gdb_stdout); + { + struct frame_id frame_id = get_frame_id (fi); + + print_frame_local_vars (fi, 1, gdb_stdout); + + /* print_frame_local_vars invalidates FI. */ + fi = frame_find_by_id (frame_id); + if (fi == NULL) + { + trailing = NULL; + warning (_("Unable to restore previously selected frame.")); + break; + } + } /* Save the last frame to check for error conditions. */ trailing = fi; @@ -1815,7 +1857,7 @@ iterate_over_block_locals (struct block *b, iterate_over_block_arg_local_vars_cb cb, void *cb_data) { - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym; ALL_BLOCK_SYMBOLS (b, iter, sym) @@ -1828,6 +1870,8 @@ iterate_over_block_locals (struct block *b, case LOC_COMPUTED: if (SYMBOL_IS_ARGUMENT (sym)) break; + if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN) + break; (*cb) (SYMBOL_PRINT_NAME (sym), sym, cb_data); break; @@ -1852,7 +1896,7 @@ static int print_block_frame_labels (struct gdbarch *gdbarch, struct block *b, int *have_default, struct ui_file *stream) { - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym; int values_printed = 0; @@ -1913,7 +1957,7 @@ iterate_over_block_local_vars (struct block *block, struct print_variable_and_value_data { - struct frame_info *frame; + struct frame_id frame_id; int num_tabs; struct ui_file *stream; int values_printed; @@ -1927,12 +1971,28 @@ do_print_variable_and_value (const char *print_name, void *cb_data) { struct print_variable_and_value_data *p = cb_data; + struct frame_info *frame; + + frame = frame_find_by_id (p->frame_id); + if (frame == NULL) + { + warning (_("Unable to restore previously selected frame.")); + return; + } + + print_variable_and_value (print_name, sym, frame, p->stream, p->num_tabs); + + /* print_variable_and_value invalidates FRAME. */ + frame = NULL; - print_variable_and_value (print_name, sym, - p->frame, p->stream, p->num_tabs); p->values_printed = 1; } +/* Print all variables from the innermost up to the function block of FRAME. + Print them with values to STREAM indented by NUM_TABS. + + This function will invalidate FRAME. */ + static void print_frame_local_vars (struct frame_info *frame, int num_tabs, struct ui_file *stream) @@ -1955,7 +2015,7 @@ print_frame_local_vars (struct frame_info *frame, int num_tabs, return; } - cb_data.frame = frame; + cb_data.frame_id = get_frame_id (frame); cb_data.num_tabs = 4 * num_tabs; cb_data.stream = stream; cb_data.values_printed = 0; @@ -1964,86 +2024,13 @@ print_frame_local_vars (struct frame_info *frame, int num_tabs, do_print_variable_and_value, &cb_data); + /* do_print_variable_and_value invalidates FRAME. */ + frame = NULL; + if (!cb_data.values_printed) fprintf_filtered (stream, _("No locals.\n")); } -/* Same, but print labels. */ - -static void -print_frame_label_vars (struct frame_info *frame, int this_level_only, - struct ui_file *stream) -{ -#if 1 - fprintf_filtered (stream, "print_frame_label_vars disabled.\n"); -#else - struct blockvector *bl; - struct block *block = get_frame_block (frame, 0); - struct gdbarch *gdbarch = get_frame_arch (frame); - int values_printed = 0; - int index, have_default = 0; - char *blocks_printed; - CORE_ADDR pc = get_frame_pc (frame); - - if (block == 0) - { - fprintf_filtered (stream, "No symbol table info available.\n"); - return; - } - - bl = blockvector_for_pc (BLOCK_END (block) - 4, &index); - blocks_printed = alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); - memset (blocks_printed, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); - - while (block != 0) - { - CORE_ADDR end = BLOCK_END (block) - 4; - int last_index; - - if (bl != blockvector_for_pc (end, &index)) - error (_("blockvector blotch")); - if (BLOCKVECTOR_BLOCK (bl, index) != block) - error (_("blockvector botch")); - last_index = BLOCKVECTOR_NBLOCKS (bl); - index += 1; - - /* Don't print out blocks that have gone by. */ - while (index < last_index - && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc) - index++; - - while (index < last_index - && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end) - { - if (blocks_printed[index] == 0) - { - if (print_block_frame_labels (gdbarch, - BLOCKVECTOR_BLOCK (bl, index), - &have_default, stream)) - values_printed = 1; - blocks_printed[index] = 1; - } - index++; - } - if (have_default) - return; - if (values_printed && this_level_only) - return; - - /* After handling the function's top-level block, stop. Don't - 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); - } - - if (!values_printed && !this_level_only) - fprintf_filtered (stream, _("No catches.\n")); -#endif -} - void locals_info (char *args, int from_tty) { @@ -2051,14 +2038,6 @@ locals_info (char *args, int from_tty) 0, gdb_stdout); } -static void -catch_info (char *ignore, int from_tty) -{ - /* Assume g++ compiled code; old GDB 4.16 behaviour. */ - print_frame_label_vars (get_selected_frame (_("No frame selected.")), - 0, gdb_stdout); -} - /* Iterate over all the argument variables in block B. Returns 1 if any argument was walked; 0 otherwise. */ @@ -2068,7 +2047,7 @@ iterate_over_block_arg_vars (struct block *b, iterate_over_block_arg_local_vars_cb cb, void *cb_data) { - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym, *sym2; ALL_BLOCK_SYMBOLS (b, iter, sym) @@ -2094,6 +2073,11 @@ iterate_over_block_arg_vars (struct block *b, } } +/* Print all argument variables of the function of FRAME. + Print them with values to STREAM. + + This function will invalidate FRAME. */ + static void print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream) { @@ -2114,7 +2098,7 @@ print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream) return; } - cb_data.frame = frame; + cb_data.frame_id = get_frame_id (frame); cb_data.num_tabs = 0; cb_data.stream = gdb_stdout; cb_data.values_printed = 0; @@ -2122,6 +2106,9 @@ print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream) iterate_over_block_arg_vars (SYMBOL_BLOCK_VALUE (func), do_print_variable_and_value, &cb_data); + /* do_print_variable_and_value invalidates FRAME. */ + frame = NULL; + if (!cb_data.values_printed) fprintf_filtered (stream, _("No arguments.\n")); } @@ -2312,10 +2299,13 @@ down_command (char *count_exp, int from_tty) void return_command (char *retval_exp, int from_tty) { + /* Initialize it just to avoid a GCC false warning. */ + enum return_value_convention rv_conv = RETURN_VALUE_STRUCT_CONVENTION; struct frame_info *thisframe; struct gdbarch *gdbarch; struct symbol *thisfun; struct value *return_value = NULL; + struct value *function = NULL; const char *query_prefix = ""; thisframe = get_selected_frame ("No selected frame."); @@ -2345,7 +2335,8 @@ return_command (char *retval_exp, int from_tty) return_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (thisfun)); if (return_type == NULL) { - if (retval_expr->elts[0].opcode != UNOP_CAST) + if (retval_expr->elts[0].opcode != UNOP_CAST + && retval_expr->elts[0].opcode != UNOP_CAST_TYPE) error (_("Return value type not available for selected " "stack frame.\n" "Please use an explicit cast of the value to return.")); @@ -2360,6 +2351,10 @@ return_command (char *retval_exp, int from_tty) if (value_lazy (return_value)) value_fetch_lazy (return_value); + if (thisfun != NULL) + function = read_var_value (thisfun, thisframe); + + rv_conv = RETURN_VALUE_REGISTER_CONVENTION; if (TYPE_CODE (return_type) == TYPE_CODE_VOID) /* If the return-type is "void", don't try to find the return-value's location. However, do still evaluate the @@ -2367,15 +2362,18 @@ return_command (char *retval_exp, int from_tty) is discarded, side effects such as "return i++" still occur. */ return_value = NULL; - else if (thisfun != NULL - && using_struct_return (gdbarch, - SYMBOL_TYPE (thisfun), return_type)) + else if (thisfun != NULL) { - query_prefix = "The location at which to store the " - "function's return value is unknown.\n" - "If you continue, the return value " - "that you specified will be ignored.\n"; - return_value = NULL; + rv_conv = struct_return_convention (gdbarch, function, return_type); + if (rv_conv == RETURN_VALUE_STRUCT_CONVENTION + || rv_conv == RETURN_VALUE_ABI_RETURNS_ADDRESS) + { + query_prefix = "The location at which to store the " + "function's return value is unknown.\n" + "If you continue, the return value " + "that you specified will be ignored.\n"; + return_value = NULL; + } } } @@ -2404,12 +2402,10 @@ return_command (char *retval_exp, int from_tty) { struct type *return_type = value_type (return_value); struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ()); - struct type *func_type = thisfun == NULL ? NULL : SYMBOL_TYPE (thisfun); - 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, + gdb_assert (rv_conv != RETURN_VALUE_STRUCT_CONVENTION + && rv_conv != RETURN_VALUE_ABI_RETURNS_ADDRESS); + gdbarch_return_value (gdbarch, function, return_type, get_current_regcache (), NULL /*read*/, value_contents (return_value) /*write*/); } @@ -2449,7 +2445,7 @@ func_command (char *arg, int from_tty) return; frame = parse_frame_specification ("0"); - sals = decode_line_spec (arg, DECODE_LINE_FUNFIRSTLINE); + sals = decode_line_with_current_source (arg, DECODE_LINE_FUNFIRSTLINE); cleanups = make_cleanup (xfree, sals.sals); func_bounds = (struct function_bounds *) xmalloc ( sizeof (struct function_bounds) * sals.nelts); @@ -2615,9 +2611,6 @@ Usage: T \n")); Select the stack frame that contains .\n\ Usage: func \n")); - add_info ("catch", catch_info, - _("Exceptions that can be caught in the current stack frame.")); - add_setshow_enum_cmd ("frame-arguments", class_stack, print_frame_arguments_choices, &print_frame_arguments, _("Set printing of non-scalar frame arguments"), diff --git a/contrib/gdb-7/gdb/stack.h b/contrib/gdb-7/gdb/stack.h index 172d7c2f26..841ad4377b 100644 --- a/contrib/gdb-7/gdb/stack.h +++ b/contrib/gdb-7/gdb/stack.h @@ -1,6 +1,6 @@ /* Stack manipulation commands, for GDB the GNU Debugger. - Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,7 +22,7 @@ void select_frame_command (char *level_exp, int from_tty); -void find_frame_funname (struct frame_info *frame, char **funname, +void find_frame_funname (struct frame_info *frame, const char **funname, enum language *funlang, struct symbol **funcp); typedef void (*iterate_over_block_arg_local_vars_cb) (const char *print_name, diff --git a/contrib/gdb-7/gdb/stap-probe.c b/contrib/gdb-7/gdb/stap-probe.c new file mode 100644 index 0000000000..9b6730450b --- /dev/null +++ b/contrib/gdb-7/gdb/stap-probe.c @@ -0,0 +1,1583 @@ +/* SystemTap probe support for GDB. + + Copyright (C) 2012-2013 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 "stap-probe.h" +#include "probe.h" +#include "vec.h" +#include "ui-out.h" +#include "objfiles.h" +#include "arch-utils.h" +#include "command.h" +#include "gdbcmd.h" +#include "filenames.h" +#include "value.h" +#include "exceptions.h" +#include "ax.h" +#include "ax-gdb.h" +#include "complaints.h" +#include "cli/cli-utils.h" +#include "linespec.h" +#include "user-regs.h" +#include "parser-defs.h" +#include "language.h" +#include "elf-bfd.h" + +#include + +/* The name of the SystemTap section where we will find information about + the probes. */ + +#define STAP_BASE_SECTION_NAME ".stapsdt.base" + +/* Forward declaration. */ + +static const struct probe_ops stap_probe_ops; + +/* Should we display debug information for the probe's argument expression + parsing? */ + +static unsigned int stap_expression_debug = 0; + +/* The various possibilities of bitness defined for a probe's argument. + + The relationship is: + + - STAP_ARG_BITNESS_UNDEFINED: The user hasn't specified the bitness. + - STAP_ARG_BITNESS_32BIT_UNSIGNED: argument string starts with `4@'. + - STAP_ARG_BITNESS_32BIT_SIGNED: argument string starts with `-4@'. + - STAP_ARG_BITNESS_64BIT_UNSIGNED: argument string starts with `8@'. + - STAP_ARG_BITNESS_64BIT_SIGNED: argument string starts with `-8@'. */ + +enum stap_arg_bitness +{ + STAP_ARG_BITNESS_UNDEFINED, + STAP_ARG_BITNESS_32BIT_UNSIGNED, + STAP_ARG_BITNESS_32BIT_SIGNED, + STAP_ARG_BITNESS_64BIT_UNSIGNED, + STAP_ARG_BITNESS_64BIT_SIGNED, +}; + +/* The following structure represents a single argument for the probe. */ + +struct stap_probe_arg +{ + /* The bitness of this argument. */ + enum stap_arg_bitness bitness; + + /* The corresponding `struct type *' to the bitness. */ + struct type *atype; + + /* The argument converted to an internal GDB expression. */ + struct expression *aexpr; +}; + +typedef struct stap_probe_arg stap_probe_arg_s; +DEF_VEC_O (stap_probe_arg_s); + +struct stap_probe +{ + /* Generic information about the probe. This shall be the first element + of this struct, in order to maintain binary compatibility with the + `struct probe' and be able to fully abstract it. */ + struct probe p; + + /* If the probe has a semaphore associated, then this is the value of + it. */ + CORE_ADDR sem_addr; + + unsigned int args_parsed : 1; + union + { + const char *text; + + /* Information about each argument. This is an array of `stap_probe_arg', + with each entry representing one argument. */ + VEC (stap_probe_arg_s) *vec; + } + args_u; +}; + +/* When parsing the arguments, we have to establish different precedences + for the various kinds of asm operators. This enumeration represents those + precedences. + + This logic behind this is available at + , or using + the command "info '(as)Infix Ops'". */ + +enum stap_operand_prec +{ + /* Lowest precedence, used for non-recognized operands or for the beginning + of the parsing process. */ + STAP_OPERAND_PREC_NONE = 0, + + /* Precedence of logical OR. */ + STAP_OPERAND_PREC_LOGICAL_OR, + + /* Precedence of logical AND. */ + STAP_OPERAND_PREC_LOGICAL_AND, + + /* Precedence of additive (plus, minus) and comparative (equal, less, + greater-than, etc) operands. */ + STAP_OPERAND_PREC_ADD_CMP, + + /* Precedence of bitwise operands (bitwise OR, XOR, bitwise AND, + logical NOT). */ + STAP_OPERAND_PREC_BITWISE, + + /* Precedence of multiplicative operands (multiplication, division, + remainder, left shift and right shift). */ + STAP_OPERAND_PREC_MUL +}; + +static void stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs, + enum stap_operand_prec prec); + +static void stap_parse_argument_conditionally (struct stap_parse_info *p); + +/* Returns 1 if *S is an operator, zero otherwise. */ + +static int stap_is_operator (const char *op); + +static void +show_stapexpressiondebug (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("SystemTap Probe expression debugging is %s.\n"), + value); +} + +/* Returns the operator precedence level of OP, or STAP_OPERAND_PREC_NONE + if the operator code was not recognized. */ + +static enum stap_operand_prec +stap_get_operator_prec (enum exp_opcode op) +{ + switch (op) + { + case BINOP_LOGICAL_OR: + return STAP_OPERAND_PREC_LOGICAL_OR; + + case BINOP_LOGICAL_AND: + return STAP_OPERAND_PREC_LOGICAL_AND; + + case BINOP_ADD: + case BINOP_SUB: + case BINOP_EQUAL: + case BINOP_NOTEQUAL: + case BINOP_LESS: + case BINOP_LEQ: + case BINOP_GTR: + case BINOP_GEQ: + return STAP_OPERAND_PREC_ADD_CMP; + + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_XOR: + case UNOP_LOGICAL_NOT: + return STAP_OPERAND_PREC_BITWISE; + + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_LSH: + case BINOP_RSH: + return STAP_OPERAND_PREC_MUL; + + default: + return STAP_OPERAND_PREC_NONE; + } +} + +/* Given S, read the operator in it and fills the OP pointer with its code. + Return 1 on success, zero if the operator was not recognized. */ + +static enum exp_opcode +stap_get_opcode (const char **s) +{ + const char c = **s; + enum exp_opcode op; + + *s += 1; + + switch (c) + { + case '*': + op = BINOP_MUL; + break; + + case '/': + op = BINOP_DIV; + break; + + case '%': + op = BINOP_REM; + break; + + case '<': + op = BINOP_LESS; + if (**s == '<') + { + *s += 1; + op = BINOP_LSH; + } + else if (**s == '=') + { + *s += 1; + op = BINOP_LEQ; + } + else if (**s == '>') + { + *s += 1; + op = BINOP_NOTEQUAL; + } + break; + + case '>': + op = BINOP_GTR; + if (**s == '>') + { + *s += 1; + op = BINOP_RSH; + } + else if (**s == '=') + { + *s += 1; + op = BINOP_GEQ; + } + break; + + case '|': + op = BINOP_BITWISE_IOR; + if (**s == '|') + { + *s += 1; + op = BINOP_LOGICAL_OR; + } + break; + + case '&': + op = BINOP_BITWISE_AND; + if (**s == '&') + { + *s += 1; + op = BINOP_LOGICAL_AND; + } + break; + + case '^': + op = BINOP_BITWISE_XOR; + break; + + case '!': + op = UNOP_LOGICAL_NOT; + break; + + case '+': + op = BINOP_ADD; + break; + + case '-': + op = BINOP_SUB; + break; + + case '=': + gdb_assert (**s == '='); + op = BINOP_EQUAL; + break; + + default: + internal_error (__FILE__, __LINE__, + _("Invalid opcode in expression `%s' for SystemTap" + "probe"), *s); + } + + return op; +} + +/* Given the bitness of the argument, represented by B, return the + corresponding `struct type *'. */ + +static struct type * +stap_get_expected_argument_type (struct gdbarch *gdbarch, + enum stap_arg_bitness b) +{ + switch (b) + { + case STAP_ARG_BITNESS_UNDEFINED: + if (gdbarch_addr_bit (gdbarch) == 32) + return builtin_type (gdbarch)->builtin_uint32; + else + return builtin_type (gdbarch)->builtin_uint64; + + case STAP_ARG_BITNESS_32BIT_SIGNED: + return builtin_type (gdbarch)->builtin_int32; + + case STAP_ARG_BITNESS_32BIT_UNSIGNED: + return builtin_type (gdbarch)->builtin_uint32; + + case STAP_ARG_BITNESS_64BIT_SIGNED: + return builtin_type (gdbarch)->builtin_int64; + + case STAP_ARG_BITNESS_64BIT_UNSIGNED: + return builtin_type (gdbarch)->builtin_uint64; + + default: + internal_error (__FILE__, __LINE__, + _("Undefined bitness for probe.")); + break; + } +} + +/* Function responsible for parsing a register operand according to + SystemTap parlance. Assuming: + + RP = register prefix + RS = register suffix + RIP = register indirection prefix + RIS = register indirection suffix + + Then a register operand can be: + + [RIP] [RP] REGISTER [RS] [RIS] + + This function takes care of a register's indirection, displacement and + direct access. It also takes into consideration the fact that some + registers are named differently inside and outside GDB, e.g., PPC's + general-purpose registers are represented by integers in the assembly + language (e.g., `15' is the 15th general-purpose register), but inside + GDB they have a prefix (the letter `r') appended. */ + +static void +stap_parse_register_operand (struct stap_parse_info *p) +{ + /* Simple flag to indicate whether we have seen a minus signal before + certain number. */ + int got_minus = 0; + + /* Flags to indicate whether this register access is being displaced and/or + indirected. */ + int disp_p = 0, indirect_p = 0; + struct gdbarch *gdbarch = p->gdbarch; + + /* Needed to generate the register name as a part of an expression. */ + struct stoken str; + + /* Variables used to extract the register name from the probe's + argument. */ + const char *start; + char *regname; + int len; + + /* Prefixes for the parser. */ + const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch); + const char *reg_ind_prefix + = gdbarch_stap_register_indirection_prefix (gdbarch); + const char *gdb_reg_prefix = gdbarch_stap_gdb_register_prefix (gdbarch); + int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0; + int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0; + int gdb_reg_prefix_len = gdb_reg_prefix ? strlen (gdb_reg_prefix) : 0; + + /* Suffixes for the parser. */ + const char *reg_suffix = gdbarch_stap_register_suffix (gdbarch); + const char *reg_ind_suffix + = gdbarch_stap_register_indirection_suffix (gdbarch); + const char *gdb_reg_suffix = gdbarch_stap_gdb_register_suffix (gdbarch); + int reg_suffix_len = reg_suffix ? strlen (reg_suffix) : 0; + int reg_ind_suffix_len = reg_ind_suffix ? strlen (reg_ind_suffix) : 0; + int gdb_reg_suffix_len = gdb_reg_suffix ? strlen (gdb_reg_suffix) : 0; + + /* Checking for a displacement argument. */ + if (*p->arg == '+') + { + /* If it's a plus sign, we don't need to do anything, just advance the + pointer. */ + ++p->arg; + } + + if (*p->arg == '-') + { + got_minus = 1; + ++p->arg; + } + + if (isdigit (*p->arg)) + { + /* The value of the displacement. */ + long displacement; + + disp_p = 1; + displacement = strtol (p->arg, (char **) &p->arg, 10); + + /* Generating the expression for the displacement. */ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type (gdbarch)->builtin_long); + write_exp_elt_longcst (displacement); + write_exp_elt_opcode (OP_LONG); + if (got_minus) + write_exp_elt_opcode (UNOP_NEG); + } + + /* Getting rid of register indirection prefix. */ + if (reg_ind_prefix + && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0) + { + indirect_p = 1; + p->arg += reg_ind_prefix_len; + } + + if (disp_p && !indirect_p) + error (_("Invalid register displacement syntax on expression `%s'."), + p->saved_arg); + + /* Getting rid of register prefix. */ + if (reg_prefix && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0) + p->arg += reg_prefix_len; + + /* Now we should have only the register name. Let's extract it and get + the associated number. */ + start = p->arg; + + /* We assume the register name is composed by letters and numbers. */ + while (isalnum (*p->arg)) + ++p->arg; + + len = p->arg - start; + + regname = alloca (len + gdb_reg_prefix_len + gdb_reg_suffix_len + 1); + regname[0] = '\0'; + + /* We only add the GDB's register prefix/suffix if we are dealing with + a numeric register. */ + if (gdb_reg_prefix && isdigit (*start)) + { + strncpy (regname, gdb_reg_prefix, gdb_reg_prefix_len); + strncpy (regname + gdb_reg_prefix_len, start, len); + + if (gdb_reg_suffix) + strncpy (regname + gdb_reg_prefix_len + len, + gdb_reg_suffix, gdb_reg_suffix_len); + + len += gdb_reg_prefix_len + gdb_reg_suffix_len; + } + else + strncpy (regname, start, len); + + regname[len] = '\0'; + + /* Is this a valid register name? */ + if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1) + error (_("Invalid register name `%s' on expression `%s'."), + regname, p->saved_arg); + + write_exp_elt_opcode (OP_REGISTER); + str.ptr = regname; + str.length = len; + write_exp_string (str); + write_exp_elt_opcode (OP_REGISTER); + + if (indirect_p) + { + if (disp_p) + write_exp_elt_opcode (BINOP_ADD); + + /* Casting to the expected type. */ + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (lookup_pointer_type (p->arg_type)); + write_exp_elt_opcode (UNOP_CAST); + + write_exp_elt_opcode (UNOP_IND); + } + + /* Getting rid of the register name suffix. */ + if (reg_suffix) + { + if (strncmp (p->arg, reg_suffix, reg_suffix_len) != 0) + error (_("Missing register name suffix `%s' on expression `%s'."), + reg_suffix, p->saved_arg); + + p->arg += reg_suffix_len; + } + + /* Getting rid of the register indirection suffix. */ + if (indirect_p && reg_ind_suffix) + { + if (strncmp (p->arg, reg_ind_suffix, reg_ind_suffix_len) != 0) + error (_("Missing indirection suffix `%s' on expression `%s'."), + reg_ind_suffix, p->saved_arg); + + p->arg += reg_ind_suffix_len; + } +} + +/* This function is responsible for parsing a single operand. + + A single operand can be: + + - an unary operation (e.g., `-5', `~2', or even with subexpressions + like `-(2 + 1)') + - a register displacement, which will be treated as a register + operand (e.g., `-4(%eax)' on x86) + - a numeric constant, or + - a register operand (see function `stap_parse_register_operand') + + The function also calls special-handling functions to deal with + unrecognized operands, allowing arch-specific parsers to be + created. */ + +static void +stap_parse_single_operand (struct stap_parse_info *p) +{ + struct gdbarch *gdbarch = p->gdbarch; + + /* Prefixes for the parser. */ + const char *const_prefix = gdbarch_stap_integer_prefix (gdbarch); + const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch); + const char *reg_ind_prefix + = gdbarch_stap_register_indirection_prefix (gdbarch); + int const_prefix_len = const_prefix ? strlen (const_prefix) : 0; + int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0; + int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0; + + /* Suffixes for the parser. */ + const char *const_suffix = gdbarch_stap_integer_suffix (gdbarch); + int const_suffix_len = const_suffix ? strlen (const_suffix) : 0; + + /* We first try to parse this token as a "special token". */ + if (gdbarch_stap_parse_special_token_p (gdbarch)) + { + int ret = gdbarch_stap_parse_special_token (gdbarch, p); + + if (ret) + { + /* If the return value of the above function is not zero, + it means it successfully parsed the special token. + + If it is NULL, we try to parse it using our method. */ + return; + } + } + + if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+') + { + char c = *p->arg; + int number; + + /* We use this variable to do a lookahead. */ + const char *tmp = p->arg; + + ++tmp; + + /* This is an unary operation. Here is a list of allowed tokens + here: + + - numeric literal; + - number (from register displacement) + - subexpression (beginning with `(') + + We handle the register displacement here, and the other cases + recursively. */ + if (p->inside_paren_p) + tmp = skip_spaces_const (tmp); + + if (isdigit (*tmp)) + number = strtol (tmp, (char **) &tmp, 10); + + if (!reg_ind_prefix + || strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0) + { + /* This is not a displacement. We skip the operator, and deal + with it later. */ + ++p->arg; + stap_parse_argument_conditionally (p); + if (c == '-') + write_exp_elt_opcode (UNOP_NEG); + else if (c == '~') + write_exp_elt_opcode (UNOP_COMPLEMENT); + } + else + { + /* If we are here, it means it is a displacement. The only + operations allowed here are `-' and `+'. */ + if (c == '~') + error (_("Invalid operator `%c' for register displacement " + "on expression `%s'."), c, p->saved_arg); + + stap_parse_register_operand (p); + } + } + else if (isdigit (*p->arg)) + { + /* A temporary variable, needed for lookahead. */ + const char *tmp = p->arg; + long number; + + /* We can be dealing with a numeric constant (if `const_prefix' is + NULL), or with a register displacement. */ + number = strtol (tmp, (char **) &tmp, 10); + + if (p->inside_paren_p) + tmp = skip_spaces_const (tmp); + if (!const_prefix && reg_ind_prefix + && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0) + { + /* We are dealing with a numeric constant. */ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type (gdbarch)->builtin_long); + write_exp_elt_longcst (number); + write_exp_elt_opcode (OP_LONG); + + p->arg = tmp; + + if (const_suffix) + { + if (strncmp (p->arg, const_suffix, const_suffix_len) == 0) + p->arg += const_suffix_len; + else + error (_("Invalid constant suffix on expression `%s'."), + p->saved_arg); + } + } + else if (reg_ind_prefix + && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) == 0) + stap_parse_register_operand (p); + else + error (_("Unknown numeric token on expression `%s'."), + p->saved_arg); + } + else if (const_prefix + && strncmp (p->arg, const_prefix, const_prefix_len) == 0) + { + /* We are dealing with a numeric constant. */ + long number; + + p->arg += const_prefix_len; + number = strtol (p->arg, (char **) &p->arg, 10); + + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type (gdbarch)->builtin_long); + write_exp_elt_longcst (number); + write_exp_elt_opcode (OP_LONG); + + if (const_suffix) + { + if (strncmp (p->arg, const_suffix, const_suffix_len) == 0) + p->arg += const_suffix_len; + else + error (_("Invalid constant suffix on expression `%s'."), + p->saved_arg); + } + } + else if ((reg_prefix + && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0) + || (reg_ind_prefix + && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0)) + stap_parse_register_operand (p); + else + error (_("Operator `%c' not recognized on expression `%s'."), + *p->arg, p->saved_arg); +} + +/* This function parses an argument conditionally, based on single or + non-single operands. A non-single operand would be a parenthesized + expression (e.g., `(2 + 1)'), and a single operand is anything that + starts with `-', `~', `+' (i.e., unary operators), a digit, or + something recognized by `gdbarch_stap_is_single_operand'. */ + +static void +stap_parse_argument_conditionally (struct stap_parse_info *p) +{ + if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' /* Unary. */ + || isdigit (*p->arg) + || gdbarch_stap_is_single_operand (p->gdbarch, p->arg)) + stap_parse_single_operand (p); + else if (*p->arg == '(') + { + /* We are dealing with a parenthesized operand. It means we + have to parse it as it was a separate expression, without + left-side or precedence. */ + ++p->arg; + p->arg = skip_spaces_const (p->arg); + ++p->inside_paren_p; + + stap_parse_argument_1 (p, 0, STAP_OPERAND_PREC_NONE); + + --p->inside_paren_p; + if (*p->arg != ')') + error (_("Missign close-paren on expression `%s'."), + p->saved_arg); + + ++p->arg; + if (p->inside_paren_p) + p->arg = skip_spaces_const (p->arg); + } + else + error (_("Cannot parse expression `%s'."), p->saved_arg); +} + +/* Helper function for `stap_parse_argument'. Please, see its comments to + better understand what this function does. */ + +static void +stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs, + enum stap_operand_prec prec) +{ + /* This is an operator-precedence parser. + + We work with left- and right-sides of expressions, and + parse them depending on the precedence of the operators + we find. */ + + if (p->inside_paren_p) + p->arg = skip_spaces_const (p->arg); + + if (!has_lhs) + { + /* We were called without a left-side, either because this is the + first call, or because we were called to parse a parenthesized + expression. It doesn't really matter; we have to parse the + left-side in order to continue the process. */ + stap_parse_argument_conditionally (p); + } + + /* Start to parse the right-side, and to "join" left and right sides + depending on the operation specified. + + This loop shall continue until we run out of characters in the input, + or until we find a close-parenthesis, which means that we've reached + the end of a sub-expression. */ + while (p->arg && *p->arg && *p->arg != ')' && !isspace (*p->arg)) + { + const char *tmp_exp_buf; + enum exp_opcode opcode; + enum stap_operand_prec cur_prec; + + if (!stap_is_operator (p->arg)) + error (_("Invalid operator `%c' on expression `%s'."), *p->arg, + p->saved_arg); + + /* We have to save the current value of the expression buffer because + the `stap_get_opcode' modifies it in order to get the current + operator. If this operator's precedence is lower than PREC, we + should return and not advance the expression buffer pointer. */ + tmp_exp_buf = p->arg; + opcode = stap_get_opcode (&tmp_exp_buf); + + cur_prec = stap_get_operator_prec (opcode); + if (cur_prec < prec) + { + /* If the precedence of the operator that we are seeing now is + lower than the precedence of the first operator seen before + this parsing process began, it means we should stop parsing + and return. */ + break; + } + + p->arg = tmp_exp_buf; + if (p->inside_paren_p) + p->arg = skip_spaces_const (p->arg); + + /* Parse the right-side of the expression. */ + stap_parse_argument_conditionally (p); + + /* While we still have operators, try to parse another + right-side, but using the current right-side as a left-side. */ + while (*p->arg && stap_is_operator (p->arg)) + { + enum exp_opcode lookahead_opcode; + enum stap_operand_prec lookahead_prec; + + /* Saving the current expression buffer position. The explanation + is the same as above. */ + tmp_exp_buf = p->arg; + lookahead_opcode = stap_get_opcode (&tmp_exp_buf); + lookahead_prec = stap_get_operator_prec (lookahead_opcode); + + if (lookahead_prec <= prec) + { + /* If we are dealing with an operator whose precedence is lower + than the first one, just abandon the attempt. */ + break; + } + + /* Parse the right-side of the expression, but since we already + have a left-side at this point, set `has_lhs' to 1. */ + stap_parse_argument_1 (p, 1, lookahead_prec); + } + + write_exp_elt_opcode (opcode); + } +} + +/* Parse a probe's argument. + + Assuming that: + + LP = literal integer prefix + LS = literal integer suffix + + RP = register prefix + RS = register suffix + + RIP = register indirection prefix + RIS = register indirection suffix + + This routine assumes that arguments' tokens are of the form: + + - [LP] NUMBER [LS] + - [RP] REGISTER [RS] + - [RIP] [RP] REGISTER [RS] [RIS] + - If we find a number without LP, we try to parse it as a literal integer + constant (if LP == NULL), or as a register displacement. + - We count parenthesis, and only skip whitespaces if we are inside them. + - If we find an operator, we skip it. + + This function can also call a special function that will try to match + unknown tokens. It will return 1 if the argument has been parsed + successfully, or zero otherwise. */ + +static struct expression * +stap_parse_argument (const char **arg, struct type *atype, + struct gdbarch *gdbarch) +{ + struct stap_parse_info p; + struct cleanup *back_to; + + /* We need to initialize the expression buffer, in order to begin + our parsing efforts. The language here does not matter, since we + are using our own parser. */ + initialize_expout (10, current_language, gdbarch); + back_to = make_cleanup (free_current_contents, &expout); + + p.saved_arg = *arg; + p.arg = *arg; + p.arg_type = atype; + p.gdbarch = gdbarch; + p.inside_paren_p = 0; + + stap_parse_argument_1 (&p, 0, STAP_OPERAND_PREC_NONE); + + discard_cleanups (back_to); + + gdb_assert (p.inside_paren_p == 0); + + /* Casting the final expression to the appropriate type. */ + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (atype); + write_exp_elt_opcode (UNOP_CAST); + + reallocate_expout (); + + p.arg = skip_spaces_const (p.arg); + *arg = p.arg; + + return expout; +} + +/* Function which parses an argument string from PROBE, correctly splitting + the arguments and storing their information in properly ways. + + Consider the following argument string (x86 syntax): + + `4@%eax 4@$10' + + We have two arguments, `%eax' and `$10', both with 32-bit unsigned bitness. + This function basically handles them, properly filling some structures with + this information. */ + +static void +stap_parse_probe_arguments (struct stap_probe *probe) +{ + const char *cur; + struct gdbarch *gdbarch = get_objfile_arch (probe->p.objfile); + + gdb_assert (!probe->args_parsed); + cur = probe->args_u.text; + probe->args_parsed = 1; + probe->args_u.vec = NULL; + + if (!cur || !*cur || *cur == ':') + return; + + while (*cur) + { + struct stap_probe_arg arg; + enum stap_arg_bitness b; + int got_minus = 0; + struct expression *expr; + + memset (&arg, 0, sizeof (arg)); + + /* We expect to find something like: + + N@OP + + Where `N' can be [+,-][4,8]. This is not mandatory, so + we check it here. If we don't find it, go to the next + state. */ + if ((*cur == '-' && cur[1] && cur[2] != '@') + && cur[1] != '@') + arg.bitness = STAP_ARG_BITNESS_UNDEFINED; + else + { + if (*cur == '-') + { + /* Discard the `-'. */ + ++cur; + got_minus = 1; + } + + if (*cur == '4') + b = (got_minus ? STAP_ARG_BITNESS_32BIT_SIGNED + : STAP_ARG_BITNESS_32BIT_UNSIGNED); + else if (*cur == '8') + b = (got_minus ? STAP_ARG_BITNESS_64BIT_SIGNED + : STAP_ARG_BITNESS_64BIT_UNSIGNED); + else + { + /* We have an error, because we don't expect anything + except 4 and 8. */ + complaint (&symfile_complaints, + _("unrecognized bitness `%c' for probe `%s'"), + *cur, probe->p.name); + return; + } + + arg.bitness = b; + arg.atype = stap_get_expected_argument_type (gdbarch, b); + + /* Discard the number and the `@' sign. */ + cur += 2; + } + + expr = stap_parse_argument (&cur, arg.atype, gdbarch); + + if (stap_expression_debug) + dump_raw_expression (expr, gdb_stdlog, + "before conversion to prefix form"); + + prefixify_expression (expr); + + if (stap_expression_debug) + dump_prefix_expression (expr, gdb_stdlog); + + arg.aexpr = expr; + + /* Start it over again. */ + cur = skip_spaces_const (cur); + + VEC_safe_push (stap_probe_arg_s, probe->args_u.vec, &arg); + } +} + +/* Given PROBE, returns the number of arguments present in that probe's + argument string. */ + +static unsigned +stap_get_probe_argument_count (struct probe *probe_generic) +{ + struct stap_probe *probe = (struct stap_probe *) probe_generic; + + gdb_assert (probe_generic->pops == &stap_probe_ops); + + if (!probe->args_parsed) + stap_parse_probe_arguments (probe); + + gdb_assert (probe->args_parsed); + return VEC_length (stap_probe_arg_s, probe->args_u.vec); +} + +/* Return 1 if OP is a valid operator inside a probe argument, or zero + otherwise. */ + +static int +stap_is_operator (const char *op) +{ + int ret = 1; + + switch (*op) + { + case '*': + case '/': + case '%': + case '^': + case '!': + case '+': + case '-': + case '<': + case '>': + case '|': + case '&': + break; + + case '=': + if (op[1] != '=') + ret = 0; + break; + + default: + /* We didn't find any operator. */ + ret = 0; + } + + return ret; +} + +static struct stap_probe_arg * +stap_get_arg (struct stap_probe *probe, unsigned n) +{ + if (!probe->args_parsed) + stap_parse_probe_arguments (probe); + + return VEC_index (stap_probe_arg_s, probe->args_u.vec, n); +} + +/* Evaluate the probe's argument N (indexed from 0), returning a value + corresponding to it. Assertion is thrown if N does not exist. */ + +static struct value * +stap_evaluate_probe_argument (struct probe *probe_generic, unsigned n) +{ + struct stap_probe *stap_probe = (struct stap_probe *) probe_generic; + struct stap_probe_arg *arg; + int pos = 0; + + gdb_assert (probe_generic->pops == &stap_probe_ops); + + arg = stap_get_arg (stap_probe, n); + return evaluate_subexp_standard (arg->atype, arg->aexpr, &pos, EVAL_NORMAL); +} + +/* Compile the probe's argument N (indexed from 0) to agent expression. + Assertion is thrown if N does not exist. */ + +static void +stap_compile_to_ax (struct probe *probe_generic, struct agent_expr *expr, + struct axs_value *value, unsigned n) +{ + struct stap_probe *stap_probe = (struct stap_probe *) probe_generic; + struct stap_probe_arg *arg; + union exp_element *pc; + + gdb_assert (probe_generic->pops == &stap_probe_ops); + + arg = stap_get_arg (stap_probe, n); + + pc = arg->aexpr->elts; + gen_expr (arg->aexpr, &pc, expr, value); + + require_rvalue (expr, value); + value->type = arg->atype; +} + +/* Destroy (free) the data related to PROBE. PROBE memory itself is not feed + as it is allocated from OBJFILE_OBSTACK. */ + +static void +stap_probe_destroy (struct probe *probe_generic) +{ + struct stap_probe *probe = (struct stap_probe *) probe_generic; + + gdb_assert (probe_generic->pops == &stap_probe_ops); + + if (probe->args_parsed) + { + struct stap_probe_arg *arg; + int ix; + + for (ix = 0; VEC_iterate (stap_probe_arg_s, probe->args_u.vec, ix, arg); + ++ix) + xfree (arg->aexpr); + VEC_free (stap_probe_arg_s, probe->args_u.vec); + } +} + + + +/* This is called to compute the value of one of the $_probe_arg* + convenience variables. */ + +static struct value * +compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar, + void *data) +{ + struct frame_info *frame = get_selected_frame (_("No frame selected")); + CORE_ADDR pc = get_frame_pc (frame); + int sel = (int) (uintptr_t) data; + struct probe *pc_probe; + const struct sym_probe_fns *pc_probe_fns; + unsigned n_args; + + /* SEL == -1 means "_probe_argc". */ + gdb_assert (sel >= -1); + + pc_probe = find_probe_by_pc (pc); + if (pc_probe == NULL) + error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc)); + + gdb_assert (pc_probe->objfile != NULL); + gdb_assert (pc_probe->objfile->sf != NULL); + gdb_assert (pc_probe->objfile->sf->sym_probe_fns != NULL); + + pc_probe_fns = pc_probe->objfile->sf->sym_probe_fns; + + n_args = pc_probe_fns->sym_get_probe_argument_count (pc_probe); + if (sel == -1) + return value_from_longest (builtin_type (arch)->builtin_int, n_args); + + if (sel >= n_args) + error (_("Invalid probe argument %d -- probe has %u arguments available"), + sel, n_args); + + return pc_probe_fns->sym_evaluate_probe_argument (pc_probe, sel); +} + +/* This is called to compile one of the $_probe_arg* convenience + variables into an agent expression. */ + +static void +compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr, + struct axs_value *value, void *data) +{ + CORE_ADDR pc = expr->scope; + int sel = (int) (uintptr_t) data; + struct probe *pc_probe; + const struct sym_probe_fns *pc_probe_fns; + int n_args; + + /* SEL == -1 means "_probe_argc". */ + gdb_assert (sel >= -1); + + pc_probe = find_probe_by_pc (pc); + if (pc_probe == NULL) + error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc)); + + gdb_assert (pc_probe->objfile != NULL); + gdb_assert (pc_probe->objfile->sf != NULL); + gdb_assert (pc_probe->objfile->sf->sym_probe_fns != NULL); + + pc_probe_fns = pc_probe->objfile->sf->sym_probe_fns; + + n_args = pc_probe_fns->sym_get_probe_argument_count (pc_probe); + + if (sel == -1) + { + value->kind = axs_rvalue; + value->type = builtin_type (expr->gdbarch)->builtin_int; + ax_const_l (expr, n_args); + return; + } + + gdb_assert (sel >= 0); + if (sel >= n_args) + error (_("Invalid probe argument %d -- probe has %d arguments available"), + sel, n_args); + + pc_probe_fns->sym_compile_to_ax (pc_probe, expr, value, sel); +} + + + +/* Set or clear a SystemTap semaphore. ADDRESS is the semaphore's + address. SET is zero if the semaphore should be cleared, or one + if it should be set. This is a helper function for `stap_semaphore_down' + and `stap_semaphore_up'. */ + +static void +stap_modify_semaphore (CORE_ADDR address, int set, struct gdbarch *gdbarch) +{ + gdb_byte bytes[sizeof (LONGEST)]; + /* The ABI specifies "unsigned short". */ + struct type *type = builtin_type (gdbarch)->builtin_unsigned_short; + ULONGEST value; + + if (address == 0) + return; + + /* Swallow errors. */ + if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0) + { + warning (_("Could not read the value of a SystemTap semaphore.")); + return; + } + + value = extract_unsigned_integer (bytes, TYPE_LENGTH (type), + gdbarch_byte_order (gdbarch)); + /* Note that we explicitly don't worry about overflow or + underflow. */ + if (set) + ++value; + else + --value; + + store_unsigned_integer (bytes, TYPE_LENGTH (type), + gdbarch_byte_order (gdbarch), value); + + if (target_write_memory (address, bytes, TYPE_LENGTH (type)) != 0) + warning (_("Could not write the value of a SystemTap semaphore.")); +} + +/* Set a SystemTap semaphore. SEM is the semaphore's address. Semaphores + act as reference counters, so calls to this function must be paired with + calls to `stap_semaphore_down'. + + This function and `stap_semaphore_down' race with another tool changing + the probes, but that is too rare to care. */ + +static void +stap_set_semaphore (struct probe *probe_generic, struct gdbarch *gdbarch) +{ + struct stap_probe *probe = (struct stap_probe *) probe_generic; + + gdb_assert (probe_generic->pops == &stap_probe_ops); + + stap_modify_semaphore (probe->sem_addr, 1, gdbarch); +} + +/* Clear a SystemTap semaphore. SEM is the semaphore's address. */ + +static void +stap_clear_semaphore (struct probe *probe_generic, struct gdbarch *gdbarch) +{ + struct stap_probe *probe = (struct stap_probe *) probe_generic; + + gdb_assert (probe_generic->pops == &stap_probe_ops); + + stap_modify_semaphore (probe->sem_addr, 0, gdbarch); +} + +/* Implementation of `$_probe_arg*' set of variables. */ + +static const struct internalvar_funcs probe_funcs = +{ + compute_probe_arg, + compile_probe_arg, + NULL +}; + +/* Helper function that parses the information contained in a + SystemTap's probe. Basically, the information consists in: + + - Probe's PC address; + - Link-time section address of `.stapsdt.base' section; + - Link-time address of the semaphore variable, or ZERO if the + probe doesn't have an associated semaphore; + - Probe's provider name; + - Probe's name; + - Probe's argument format + + This function returns 1 if the handling was successful, and zero + otherwise. */ + +static void +handle_stap_probe (struct objfile *objfile, struct sdt_note *el, + VEC (probe_p) **probesp, CORE_ADDR base) +{ + bfd *abfd = objfile->obfd; + int size = bfd_get_arch_size (abfd) / 8; + struct gdbarch *gdbarch = get_objfile_arch (objfile); + struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr; + CORE_ADDR base_ref; + const char *probe_args = NULL; + struct stap_probe *ret; + + ret = obstack_alloc (&objfile->objfile_obstack, sizeof (*ret)); + ret->p.pops = &stap_probe_ops; + ret->p.objfile = objfile; + + /* Provider and the name of the probe. */ + ret->p.provider = (char *) &el->data[3 * size]; + ret->p.name = memchr (ret->p.provider, '\0', + (char *) el->data + el->size - ret->p.provider); + /* Making sure there is a name. */ + if (!ret->p.name) + { + complaint (&symfile_complaints, _("corrupt probe name when " + "reading `%s'"), objfile->name); + + /* There is no way to use a probe without a name or a provider, so + returning zero here makes sense. */ + return; + } + else + ++ret->p.name; + + /* Retrieving the probe's address. */ + ret->p.address = extract_typed_address (&el->data[0], ptr_type); + + /* Link-time sh_addr of `.stapsdt.base' section. */ + base_ref = extract_typed_address (&el->data[size], ptr_type); + + /* Semaphore address. */ + ret->sem_addr = extract_typed_address (&el->data[2 * size], ptr_type); + + ret->p.address += (ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT (objfile)) + + base - base_ref); + if (ret->sem_addr) + ret->sem_addr += (ANOFFSET (objfile->section_offsets, + SECT_OFF_DATA (objfile)) + + base - base_ref); + + /* Arguments. We can only extract the argument format if there is a valid + name for this probe. */ + probe_args = memchr (ret->p.name, '\0', + (char *) el->data + el->size - ret->p.name); + + if (probe_args != NULL) + ++probe_args; + + if (probe_args == NULL || (memchr (probe_args, '\0', + (char *) el->data + el->size - ret->p.name) + != el->data + el->size - 1)) + { + complaint (&symfile_complaints, _("corrupt probe argument when " + "reading `%s'"), objfile->name); + /* If the argument string is NULL, it means some problem happened with + it. So we return 0. */ + return; + } + + ret->args_parsed = 0; + ret->args_u.text = (void *) probe_args; + + /* Successfully created probe. */ + VEC_safe_push (probe_p, *probesp, (struct probe *) ret); +} + +/* Helper function which tries to find the base address of the SystemTap + base section named STAP_BASE_SECTION_NAME. */ + +static void +get_stap_base_address_1 (bfd *abfd, asection *sect, void *obj) +{ + asection **ret = obj; + + if ((sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS)) + && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME)) + *ret = sect; +} + +/* Helper function which iterates over every section in the BFD file, + trying to find the base address of the SystemTap base section. + Returns 1 if found (setting BASE to the proper value), zero otherwise. */ + +static int +get_stap_base_address (bfd *obfd, bfd_vma *base) +{ + asection *ret = NULL; + + bfd_map_over_sections (obfd, get_stap_base_address_1, (void *) &ret); + + if (!ret) + { + complaint (&symfile_complaints, _("could not obtain base address for " + "SystemTap section on objfile `%s'."), + obfd->filename); + return 0; + } + + if (base) + *base = ret->vma; + + return 1; +} + +/* Helper function for `elf_get_probes', which gathers information about all + SystemTap probes from OBJFILE. */ + +static void +stap_get_probes (VEC (probe_p) **probesp, struct objfile *objfile) +{ + /* If we are here, then this is the first time we are parsing the + SystemTap probe's information. We basically have to count how many + probes the objfile has, and then fill in the necessary information + for each one. */ + bfd *obfd = objfile->obfd; + bfd_vma base; + struct sdt_note *iter; + unsigned save_probesp_len = VEC_length (probe_p, *probesp); + + if (objfile->separate_debug_objfile_backlink != NULL) + { + /* This is a .debug file, not the objfile itself. */ + return; + } + + if (!elf_tdata (obfd)->sdt_note_head) + { + /* There isn't any probe here. */ + return; + } + + if (!get_stap_base_address (obfd, &base)) + { + /* There was an error finding the base address for the section. + Just return NULL. */ + return; + } + + /* Parsing each probe's information. */ + for (iter = elf_tdata (obfd)->sdt_note_head; iter; iter = iter->next) + { + /* We first have to handle all the information about the + probe which is present in the section. */ + handle_stap_probe (objfile, iter, probesp, base); + } + + if (save_probesp_len == VEC_length (probe_p, *probesp)) + { + /* If we are here, it means we have failed to parse every known + probe. */ + complaint (&symfile_complaints, _("could not parse SystemTap probe(s) " + "from inferior")); + return; + } +} + +static void +stap_relocate (struct probe *probe_generic, CORE_ADDR delta) +{ + struct stap_probe *probe = (struct stap_probe *) probe_generic; + + gdb_assert (probe_generic->pops == &stap_probe_ops); + + probe->p.address += delta; + if (probe->sem_addr) + probe->sem_addr += delta; +} + +static int +stap_probe_is_linespec (const char **linespecp) +{ + static const char *const keywords[] = { "-pstap", "-probe-stap", NULL }; + + return probe_is_linespec_by_keyword (linespecp, keywords); +} + +static void +stap_gen_info_probes_table_header (VEC (info_probe_column_s) **heads) +{ + info_probe_column_s stap_probe_column; + + stap_probe_column.field_name = "semaphore"; + stap_probe_column.print_name = _("Semaphore"); + + VEC_safe_push (info_probe_column_s, *heads, &stap_probe_column); +} + +static void +stap_gen_info_probes_table_values (struct probe *probe_generic, + VEC (const_char_ptr) **ret) +{ + struct stap_probe *probe = (struct stap_probe *) probe_generic; + struct gdbarch *gdbarch; + const char *val = NULL; + + gdb_assert (probe_generic->pops == &stap_probe_ops); + + gdbarch = get_objfile_arch (probe->p.objfile); + + if (probe->sem_addr) + val = print_core_address (gdbarch, probe->sem_addr); + + VEC_safe_push (const_char_ptr, *ret, val); +} + +/* SystemTap probe_ops. */ + +static const struct probe_ops stap_probe_ops = +{ + stap_probe_is_linespec, + stap_get_probes, + stap_relocate, + stap_get_probe_argument_count, + stap_evaluate_probe_argument, + stap_compile_to_ax, + stap_set_semaphore, + stap_clear_semaphore, + stap_probe_destroy, + stap_gen_info_probes_table_header, + stap_gen_info_probes_table_values, +}; + +/* Implementation of the `info probes stap' command. */ + +static void +info_probes_stap_command (char *arg, int from_tty) +{ + info_probes_for_ops (arg, from_tty, &stap_probe_ops); +} + +void _initialize_stap_probe (void); + +void +_initialize_stap_probe (void) +{ + VEC_safe_push (probe_ops_cp, all_probe_ops, &stap_probe_ops); + + add_setshow_zuinteger_cmd ("stap-expression", class_maintenance, + &stap_expression_debug, + _("Set SystemTap expression debugging."), + _("Show SystemTap expression debugging."), + _("When non-zero, the internal representation " + "of SystemTap expressions will be printed."), + NULL, + show_stapexpressiondebug, + &setdebuglist, &showdebuglist); + + create_internalvar_type_lazy ("_probe_argc", &probe_funcs, + (void *) (uintptr_t) -1); + create_internalvar_type_lazy ("_probe_arg0", &probe_funcs, + (void *) (uintptr_t) 0); + create_internalvar_type_lazy ("_probe_arg1", &probe_funcs, + (void *) (uintptr_t) 1); + create_internalvar_type_lazy ("_probe_arg2", &probe_funcs, + (void *) (uintptr_t) 2); + create_internalvar_type_lazy ("_probe_arg3", &probe_funcs, + (void *) (uintptr_t) 3); + create_internalvar_type_lazy ("_probe_arg4", &probe_funcs, + (void *) (uintptr_t) 4); + create_internalvar_type_lazy ("_probe_arg5", &probe_funcs, + (void *) (uintptr_t) 5); + create_internalvar_type_lazy ("_probe_arg6", &probe_funcs, + (void *) (uintptr_t) 6); + create_internalvar_type_lazy ("_probe_arg7", &probe_funcs, + (void *) (uintptr_t) 7); + create_internalvar_type_lazy ("_probe_arg8", &probe_funcs, + (void *) (uintptr_t) 8); + create_internalvar_type_lazy ("_probe_arg9", &probe_funcs, + (void *) (uintptr_t) 9); + create_internalvar_type_lazy ("_probe_arg10", &probe_funcs, + (void *) (uintptr_t) 10); + create_internalvar_type_lazy ("_probe_arg11", &probe_funcs, + (void *) (uintptr_t) 11); + + add_cmd ("stap", class_info, info_probes_stap_command, + _("\ +Show information about SystemTap static probes.\n\ +Usage: info probes stap [PROVIDER [NAME [OBJECT]]]\n\ +Each argument is a regular expression, used to select probes.\n\ +PROVIDER matches probe provider names.\n\ +NAME matches the probe names.\n\ +OBJECT matches the executable or shared library name."), + info_probes_cmdlist_get ()); + +} diff --git a/contrib/gdb-7/gdb/stap-probe.h b/contrib/gdb-7/gdb/stap-probe.h new file mode 100644 index 0000000000..eb34dbdf04 --- /dev/null +++ b/contrib/gdb-7/gdb/stap-probe.h @@ -0,0 +1,50 @@ +/* SystemTap probe support for GDB. + + Copyright (C) 2012-2013 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 (STAP_PROBE_H) +#define STAP_PROBE_H 1 + +/* Structure which holds information about the parsing process of one probe's + argument. */ + +struct stap_parse_info +{ + /* The probe's argument in a string format. */ + const char *arg; + + /* A pointer to the full chain of arguments. This is useful for printing + error messages. The parser functions should not modify this argument + directly; instead, they should use the ARG pointer above. */ + const char *saved_arg; + + /* The expected argument type (bitness), as defined in the probe's + argument. For instance, if the argument begins with `-8@', it means + the bitness is 64-bit signed. In this case, ARG_TYPE would represent + the type `int64_t'. */ + struct type *arg_type; + + /* A pointer to the current gdbarch. */ + struct gdbarch *gdbarch; + + /* Greater than zero if we are inside a parenthesized expression. Useful + for knowing when to skip spaces or not. */ + int inside_paren_p; +}; + +#endif /* !defined (STAP_PROBE_H) */ diff --git a/contrib/gdb-7/gdb/std-operator.def b/contrib/gdb-7/gdb/std-operator.def index f2f650b01b..467c1411f5 100644 --- a/contrib/gdb-7/gdb/std-operator.def +++ b/contrib/gdb-7/gdb/std-operator.def @@ -1,7 +1,6 @@ /* Standard language operator definitions for GDB, the GNU debugger. - Copyright (C) 1986, 1989, 1992, 1994, 2000, 2003, 2005, 2007-2012 - Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -105,11 +104,6 @@ OP (TERNOP_COND) /* ?: */ OP1(OP2:OP3). Return elements OP2 through OP3 of OP1. */ OP (TERNOP_SLICE) -/* A sub-string/sub-array. (The deleted) Chill syntax: OP1(OP2 UP - OP3). Return OP3 elements of OP1, starting with element - OP2. */ -OP (TERNOP_SLICE_COUNT) - /* Multidimensional subscript operator, such as Modula-2 x[a,b,...]. The dimensionality is encoded in the operator, like the number of function arguments in OP_FUNCALL, I.E. . @@ -194,12 +188,6 @@ OP (OP_COMPLEX) is executed. */ OP (OP_STRING) -/* OP_BITSTRING represents a packed bitstring constant. - Its format is the same as that of a STRUCTOP, but the bitstring - data is just made into a bitstring constant when the operation - is executed. */ -OP (OP_BITSTRING) - /* OP_ARRAY creates an array constant out of the following subexpressions. It is followed by two exp_elements, the first containing an integer that is the lower bound of the array and the second containing another @@ -216,6 +204,9 @@ OP (OP_ARRAY) It casts the value of the following subexpression. */ OP (UNOP_CAST) +/* Like UNOP_CAST, but the type is a subexpression. */ +OP (UNOP_CAST_TYPE) + /* The C++ dynamic_cast operator. */ OP (UNOP_DYNAMIC_CAST) @@ -235,6 +226,9 @@ OP (UNOP_MEMVAL) following subexpression from the TLS specified by `struct objfile'. */ OP (UNOP_MEMVAL_TLS) +/* Like UNOP_MEMVAL, but the type is supplied as a subexpression. */ +OP (UNOP_MEMVAL_TYPE) + /* UNOP_... operate on one value from a following subexpression and replace it with a result. They take no immediate arguments. */ @@ -291,19 +285,6 @@ OP (OP_OBJC_SELECTOR) a string, which, of course, is variable length. */ OP (OP_SCOPE) -/* Used to represent named structure field values in brace - initializers (or tuples as they are called in (the deleted) - Chill). - - The gcc C syntax is NAME:VALUE or .NAME=VALUE, the (the - deleted) Chill syntax is .NAME:VALUE. Multiple labels (as in - the (the deleted) Chill syntax .NAME1,.NAME2:VALUE) is - represented as if it were .NAME1:(.NAME2:VALUE) (though that is - not valid (the deleted) Chill syntax). - - The NAME is represented as for STRUCTOP_STRUCT; VALUE follows. */ -OP (OP_LABELED) - /* OP_TYPE is for parsing types, and used with the "ptype" command so we can look up types that are qualified by scope, either with the GDB "::" operator, or the Modula-2 '.' operator. */ @@ -326,3 +307,12 @@ OP (OP_DECFLOAT) /* OP_ADL_FUNC specifies that the function is to be looked up in an Argument Dependent manner (Koenig lookup). */ OP (OP_ADL_FUNC) + +/* The typeof operator. This has one expression argument, which is + evaluated solely for its type. */ +OP (OP_TYPEOF) + +/* The decltype operator. This has one expression argument, which is + evaluated solely for its type. This is similar to typeof, but has + slight different semantics. */ +OP (OP_DECLTYPE) diff --git a/contrib/gdb-7/gdb/std-regs.c b/contrib/gdb-7/gdb/std-regs.c index c5b97d6d71..c67e50e4d6 100644 --- a/contrib/gdb-7/gdb/std-regs.c +++ b/contrib/gdb-7/gdb/std-regs.c @@ -1,6 +1,6 @@ /* Builtin frame register, for GDB, the GNU debugger. - Copyright (C) 2002, 2005, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2013 Free Software Foundation, Inc. Contributed by Red Hat. diff --git a/contrib/gdb-7/gdb/stubs/ChangeLog b/contrib/gdb-7/gdb/stubs/ChangeLog new file mode 100644 index 0000000000..607fb8fcfa --- /dev/null +++ b/contrib/gdb-7/gdb/stubs/ChangeLog @@ -0,0 +1,21 @@ +2012-12-19 Joel Brobecker + + * buildvms.com: Add copyright header. + +2012-06-05 Joel Brobecker + + * ia64vms-stub.c: Adjust copyright header to follow convention + expected by gnulib's update-copyright script. + +2012-03-08 Tristan Gingold + + * sparc-stub.c: Move from .. + * sh-stub.c: Likewise. + * m68k-stub.c: Likewise. + * m32r-stub.c: Likewise. + * i386-stub.c: Likewise. + +2012-03-05 Tristan Gingold + + * buildvms.com: New file. + * ia64vms-stub.c: New file. diff --git a/contrib/gdb-7/gdb/stubs/buildvms.com b/contrib/gdb-7/gdb/stubs/buildvms.com new file mode 100644 index 0000000000..11c2cc0d0e --- /dev/null +++ b/contrib/gdb-7/gdb/stubs/buildvms.com @@ -0,0 +1,29 @@ +$! Command to build the gdb stub + +$! Copyright (C) 2012-2013 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 . + +$cc /debug/noopt /pointer=64 gdbstub +sys$library:sys$lib_c.tlb/lib +$ link/notraceback/sysexe/map=gdbstub.map/full/share=gdbstub.exe gdbstub,sys$inp +ut/opt +$deck +cluster=gdbzero +collect=gdbzero, XFER_PSECT +$eod +$ search /nowarnings gdbstub.map "DECC$" +$! Example of use. +$ DEFINE /nolog LIB$DEBUG sys$login:gdbstub.exe diff --git a/contrib/gdb-7/gdb/stubs/i386-stub.c b/contrib/gdb-7/gdb/stubs/i386-stub.c new file mode 100644 index 0000000000..04996b75cf --- /dev/null +++ b/contrib/gdb-7/gdb/stubs/i386-stub.c @@ -0,0 +1,952 @@ +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for 386 by Jim Kingdon, Cygnus Support. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + * The external function exceptionHandler() is + * used to attach a specific handler to a specific 386 vector number. + * It should use the same privilege level it runs at. It should + * install it as an interrupt gate so that interrupts are masked + * while the handler runs. + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ + +extern void putDebugChar(); /* write a single character */ +extern int getDebugChar(); /* read and return a single char */ +extern void exceptionHandler(); /* assign an exception handler */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const char hexchars[]="0123456789abcdef"; + +/* Number of registers. */ +#define NUMREGS 16 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) + +enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, + PC /* also known as eip */, + PS /* also known as eflags */, + CS, SS, DS, ES, FS, GS}; + +/* + * these should not be static cuz they can be used outside this module + */ +int registers[NUMREGS]; + +#define STACKSIZE 10000 +int remcomStack[STACKSIZE/sizeof(int)]; +static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* */ + +extern void +return_to_prog (); + +/* Restore the program's registers (including the stack pointer, which + means we get the right stack and don't have to worry about popping our + return address and any stack frames and so on) and return. */ +asm(".text"); +asm(".globl _return_to_prog"); +asm("_return_to_prog:"); +asm(" movw _registers+44, %ss"); +asm(" movl _registers+16, %esp"); +asm(" movl _registers+4, %ecx"); +asm(" movl _registers+8, %edx"); +asm(" movl _registers+12, %ebx"); +asm(" movl _registers+20, %ebp"); +asm(" movl _registers+24, %esi"); +asm(" movl _registers+28, %edi"); +asm(" movw _registers+48, %ds"); +asm(" movw _registers+52, %es"); +asm(" movw _registers+56, %fs"); +asm(" movw _registers+60, %gs"); +asm(" movl _registers+36, %eax"); +asm(" pushl %eax"); /* saved eflags */ +asm(" movl _registers+40, %eax"); +asm(" pushl %eax"); /* saved cs */ +asm(" movl _registers+32, %eax"); +asm(" pushl %eax"); /* saved eip */ +asm(" movl _registers, %eax"); +/* use iret to restore pc and flags together so + that trace flag works right. */ +asm(" iret"); + +#define BREAKPOINT() asm(" int $3"); + +/* Put the error code here just in case the user cares. */ +int gdb_i386errcode; +/* Likewise, the vector number here (since GDB only gets the signal + number through the usual means, and that's not very specific). */ +int gdb_i386vector = -1; + +/* GDB stores segment registers in 32-bit words (that's just the way + m-i386v.h is written). So zero the appropriate areas in registers. */ +#define SAVE_REGISTERS1() \ + asm ("movl %eax, _registers"); \ + asm ("movl %ecx, _registers+4"); \ + asm ("movl %edx, _registers+8"); \ + asm ("movl %ebx, _registers+12"); \ + asm ("movl %ebp, _registers+20"); \ + asm ("movl %esi, _registers+24"); \ + asm ("movl %edi, _registers+28"); \ + asm ("movw $0, %ax"); \ + asm ("movw %ds, _registers+48"); \ + asm ("movw %ax, _registers+50"); \ + asm ("movw %es, _registers+52"); \ + asm ("movw %ax, _registers+54"); \ + asm ("movw %fs, _registers+56"); \ + asm ("movw %ax, _registers+58"); \ + asm ("movw %gs, _registers+60"); \ + asm ("movw %ax, _registers+62"); +#define SAVE_ERRCODE() \ + asm ("popl %ebx"); \ + asm ("movl %ebx, _gdb_i386errcode"); +#define SAVE_REGISTERS2() \ + asm ("popl %ebx"); /* old eip */ \ + asm ("movl %ebx, _registers+32"); \ + asm ("popl %ebx"); /* old cs */ \ + asm ("movl %ebx, _registers+40"); \ + asm ("movw %ax, _registers+42"); \ + asm ("popl %ebx"); /* old eflags */ \ + asm ("movl %ebx, _registers+36"); \ + /* Now that we've done the pops, we can save the stack pointer."); */ \ + asm ("movw %ss, _registers+44"); \ + asm ("movw %ax, _registers+46"); \ + asm ("movl %esp, _registers+16"); + +/* See if mem_fault_routine is set, if so just IRET to that address. */ +#define CHECK_FAULT() \ + asm ("cmpl $0, _mem_fault_routine"); \ + asm ("jne mem_fault"); + +asm (".text"); +asm ("mem_fault:"); +/* OK to clobber temp registers; we're just going to end up in set_mem_err. */ +/* Pop error code from the stack and save it. */ +asm (" popl %eax"); +asm (" movl %eax, _gdb_i386errcode"); + +asm (" popl %eax"); /* eip */ +/* We don't want to return there, we want to return to the function + pointed to by mem_fault_routine instead. */ +asm (" movl _mem_fault_routine, %eax"); +asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */ +asm (" popl %edx"); /* eflags */ + +/* Remove this stack frame; when we do the iret, we will be going to + the start of a function, so we want the stack to look just like it + would after a "call" instruction. */ +asm (" leave"); + +/* Push the stuff that iret wants. */ +asm (" pushl %edx"); /* eflags */ +asm (" pushl %ecx"); /* cs */ +asm (" pushl %eax"); /* eip */ + +/* Zero mem_fault_routine. */ +asm (" movl $0, %eax"); +asm (" movl %eax, _mem_fault_routine"); + +asm ("iret"); + +#define CALL_HOOK() asm("call _remcomHandler"); + +/* This function is called when a i386 exception occurs. It saves + * all the cpu regs in the _registers array, munges the stack a bit, + * and invokes an exception handler (remcom_handler). + * + * stack on entry: stack on exit: + * old eflags vector number + * old cs (zero-filled to 32 bits) + * old eip + * + */ +extern void _catchException3(); +asm(".text"); +asm(".globl __catchException3"); +asm("__catchException3:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $3"); +CALL_HOOK(); + +/* Same thing for exception 1. */ +extern void _catchException1(); +asm(".text"); +asm(".globl __catchException1"); +asm("__catchException1:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $1"); +CALL_HOOK(); + +/* Same thing for exception 0. */ +extern void _catchException0(); +asm(".text"); +asm(".globl __catchException0"); +asm("__catchException0:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $0"); +CALL_HOOK(); + +/* Same thing for exception 4. */ +extern void _catchException4(); +asm(".text"); +asm(".globl __catchException4"); +asm("__catchException4:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $4"); +CALL_HOOK(); + +/* Same thing for exception 5. */ +extern void _catchException5(); +asm(".text"); +asm(".globl __catchException5"); +asm("__catchException5:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $5"); +CALL_HOOK(); + +/* Same thing for exception 6. */ +extern void _catchException6(); +asm(".text"); +asm(".globl __catchException6"); +asm("__catchException6:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $6"); +CALL_HOOK(); + +/* Same thing for exception 7. */ +extern void _catchException7(); +asm(".text"); +asm(".globl __catchException7"); +asm("__catchException7:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $7"); +CALL_HOOK(); + +/* Same thing for exception 8. */ +extern void _catchException8(); +asm(".text"); +asm(".globl __catchException8"); +asm("__catchException8:"); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $8"); +CALL_HOOK(); + +/* Same thing for exception 9. */ +extern void _catchException9(); +asm(".text"); +asm(".globl __catchException9"); +asm("__catchException9:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $9"); +CALL_HOOK(); + +/* Same thing for exception 10. */ +extern void _catchException10(); +asm(".text"); +asm(".globl __catchException10"); +asm("__catchException10:"); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $10"); +CALL_HOOK(); + +/* Same thing for exception 12. */ +extern void _catchException12(); +asm(".text"); +asm(".globl __catchException12"); +asm("__catchException12:"); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $12"); +CALL_HOOK(); + +/* Same thing for exception 16. */ +extern void _catchException16(); +asm(".text"); +asm(".globl __catchException16"); +asm("__catchException16:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $16"); +CALL_HOOK(); + +/* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */ + +/* Same thing for exception 13. */ +extern void _catchException13 (); +asm (".text"); +asm (".globl __catchException13"); +asm ("__catchException13:"); +CHECK_FAULT(); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $13"); +CALL_HOOK(); + +/* Same thing for exception 11. */ +extern void _catchException11 (); +asm (".text"); +asm (".globl __catchException11"); +asm ("__catchException11:"); +CHECK_FAULT(); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $11"); +CALL_HOOK(); + +/* Same thing for exception 14. */ +extern void _catchException14 (); +asm (".text"); +asm (".globl __catchException14"); +asm ("__catchException14:"); +CHECK_FAULT(); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $14"); +CALL_HOOK(); + +/* + * remcomHandler is a front end for handle_exception. It moves the + * stack pointer into an area reserved for debugger use. + */ +asm("_remcomHandler:"); +asm(" popl %eax"); /* pop off return address */ +asm(" popl %eax"); /* get the exception number */ +asm(" movl _stackPtr, %esp"); /* move to remcom stack area */ +asm(" pushl %eax"); /* push exception onto stack */ +asm(" call _handle_exception"); /* this never returns */ + +void +_returnFromException () +{ + return_to_prog (); +} + +int +hex (ch) + char ch; +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +/* scan for the sequence $# */ + +unsigned char * +getpacket (void) +{ + unsigned char *buffer = &remcomInBuffer[0]; + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + while (1) + { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar ()) != '$') + ; + + retry: + checksum = 0; + xmitcsum = -1; + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX - 1) + { + ch = getDebugChar (); + if (ch == '$') + goto retry; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + ch = getDebugChar (); + xmitcsum = hex (ch) << 4; + ch = getDebugChar (); + xmitcsum += hex (ch); + + if (checksum != xmitcsum) + { + if (remote_debug) + { + fprintf (stderr, + "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + putDebugChar ('-'); /* failed checksum */ + } + else + { + putDebugChar ('+'); /* successful transfer */ + + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + return &buffer[3]; + } + + return &buffer[0]; + } + } + } +} + +/* send the packet in buffer. */ + +void +putpacket (unsigned char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum % 16]); + + } + while (getDebugChar () != '+'); +} + +void +debug_error (format, parm) + char *format; + char *parm; +{ + if (remote_debug) + fprintf (stderr, format, parm); +} + +/* Address of a routine to RTE to if we get a memory fault. */ +static void (*volatile mem_fault_routine) () = NULL; + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; + +void +set_mem_err (void) +{ + mem_err = 1; +} + +/* These are separate functions so that they are so short and sweet + that the compiler won't save any registers (if there is a fault + to mem_fault, they won't get restored, so there better not be any + saved). */ +int +get_char (char *addr) +{ + return *addr; +} + +void +set_char (char *addr, int val) +{ + *addr = val; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +/* If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ +char * +mem2hex (mem, buf, count, may_fault) + char *mem; + char *buf; + int count; + int may_fault; +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = get_char (mem++); + if (may_fault && mem_err) + return (buf); + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_fault_routine = NULL; + return (buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +char * +hex2mem (buf, mem, count, may_fault) + char *buf; + char *mem; + int count; + int may_fault; +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + set_char (mem++, ch); + if (may_fault && mem_err) + return (mem); + } + if (may_fault) + mem_fault_routine = NULL; + return (mem); +} + +/* this function takes the 386 exception vector and attempts to + translate this number into a unix compatible signal value */ +int +computeSignal (int exceptionVector) +{ + int sigval; + switch (exceptionVector) + { + case 0: + sigval = 8; + break; /* divide by zero */ + case 1: + sigval = 5; + break; /* debug exception */ + case 3: + sigval = 5; + break; /* breakpoint */ + case 4: + sigval = 16; + break; /* into instruction (overflow) */ + case 5: + sigval = 16; + break; /* bound instruction */ + case 6: + sigval = 4; + break; /* Invalid opcode */ + case 7: + sigval = 8; + break; /* coprocessor not available */ + case 8: + sigval = 7; + break; /* double fault */ + case 9: + sigval = 11; + break; /* coprocessor segment overrun */ + case 10: + sigval = 11; + break; /* Invalid TSS */ + case 11: + sigval = 11; + break; /* Segment not present */ + case 12: + sigval = 11; + break; /* stack exception */ + case 13: + sigval = 11; + break; /* general protection */ + case 14: + sigval = 11; + break; /* page fault */ + case 16: + sigval = 7; + break; /* coprocessor error */ + default: + sigval = 7; /* "software generated" */ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToInt (char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex (**ptr); + if (hexValue >= 0) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* + * This function does all command procesing for interfacing to gdb. + */ +void +handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length; + char *ptr; + int newPC; + + gdb_i386vector = exceptionVector; + + if (remote_debug) + { + printf ("vector=%d, sr=0x%x, pc=0x%x\n", + exceptionVector, registers[PS], registers[PC]); + } + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + + ptr = remcomOutBuffer; + + *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[ESP]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */ + *ptr++ = ';'; + + *ptr++ = hexchars[EBP]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */ + *ptr++ = ';'; + + *ptr++ = hexchars[PC]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */ + *ptr++ = ';'; + + *ptr = '\0' + + putpacket (remcomOutBuffer); + + stepping = 0; + + while (1 == 1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + + switch (*ptr++) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (char *) registers, NUMREGBYTES, 0); + strcpy (remcomOutBuffer, "OK"); + break; + case 'P': /* set the value of a single CPU register - return OK */ + { + int regno; + + if (hexToInt (&ptr, ®no) && *ptr++ == '=') + if (regno >= 0 && regno < NUMREGS) + { + hex2mem (ptr, (char *) ®isters[regno], 4, 0); + strcpy (remcomOutBuffer, "OK"); + break; + } + + strcpy (remcomOutBuffer, "E01"); + break; + } + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem_err = 0; + mem2hex ((char *) addr, remcomOutBuffer, length, 1); + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + debug_error ("memory fault"); + } + } + + if (ptr) + { + strcpy (remcomOutBuffer, "E01"); + } + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M': + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + mem_err = 0; + hex2mem (ptr, (char *) addr, length, 1); + + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + debug_error ("memory fault"); + } + else + { + strcpy (remcomOutBuffer, "OK"); + } + + ptr = 0; + } + if (ptr) + { + strcpy (remcomOutBuffer, "E02"); + } + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 's': + stepping = 1; + case 'c': + /* try to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + newPC = registers[PC]; + + /* clear the trace bit */ + registers[PS] &= 0xfffffeff; + + /* set the trace bit if we're stepping */ + if (stepping) + registers[PS] |= 0x100; + + _returnFromException (); /* this is a jump */ + break; + + /* kill the program */ + case 'k': /* do nothing */ +#if 0 + /* Huh? This doesn't look like "nothing". + m68k-stub.c and sparc-stub.c don't have it. */ + BREAKPOINT (); +#endif + break; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void +set_debug_traps (void) +{ + stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + + exceptionHandler (0, _catchException0); + exceptionHandler (1, _catchException1); + exceptionHandler (3, _catchException3); + exceptionHandler (4, _catchException4); + exceptionHandler (5, _catchException5); + exceptionHandler (6, _catchException6); + exceptionHandler (7, _catchException7); + exceptionHandler (8, _catchException8); + exceptionHandler (9, _catchException9); + exceptionHandler (10, _catchException10); + exceptionHandler (11, _catchException11); + exceptionHandler (12, _catchException12); + exceptionHandler (13, _catchException13); + exceptionHandler (14, _catchException14); + exceptionHandler (16, _catchException16); + + initialized = 1; +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint (void) +{ + if (initialized) + BREAKPOINT (); +} diff --git a/contrib/gdb-7/gdb/stubs/ia64vms-stub.c b/contrib/gdb-7/gdb/stubs/ia64vms-stub.c new file mode 100644 index 0000000000..c4b9a138bb --- /dev/null +++ b/contrib/gdb-7/gdb/stubs/ia64vms-stub.c @@ -0,0 +1,2602 @@ +/* GDB stub for Itanium OpenVMS + Copyright (C) 2012-2013 Free Software Foundation, Inc. + + Contributed by Tristan Gingold, AdaCore. + + 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 . */ + +/* On VMS, the debugger (in our case the stub) is loaded in the process and + executed (via SYS$IMGSTA) before the main entry point of the executable. + In UNIX parlance, this is like using LD_PRELOAD and debug via installing + SIGTRAP, SIGSEGV... handlers. + + This is currently a partial implementation. In particular, modifying + registers is currently not implemented, as well as inferior procedure + calls. + + This is written in very low-level C, in order not to use the C runtime, + because it may have weird consequences on the program being debugged. +*/ + +#if __INITIAL_POINTER_SIZE != 64 +#error "Must be compiled with 64 bit pointers" +#endif + +#define __NEW_STARLET 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define VMS_PAGE_SIZE 0x2000 +#define VMS_PAGE_MASK (VMS_PAGE_SIZE - 1) + +/* Declared in lib$ots. */ +extern void ots$fill (void *addr, size_t len, unsigned char b); +extern void ots$move (void *dst, size_t len, const void *src); +extern int ots$strcmp_eql (const void *str1, size_t str1len, + const void *str2, size_t str2len); + +/* Stub port number. */ +static unsigned int serv_port = 1234; + +/* DBGEXT structure. Not declared in any header. */ +struct dbgext_control_block +{ + unsigned short dbgext$w_function_code; +#define DBGEXT$K_NEXT_TASK 3 +#define DBGEXT$K_STOP_ALL_OTHER_TASKS 31 +#define DBGEXT$K_GET_REGS 33 + unsigned short dbgext$w_facility_id; +#define CMA$_FACILITY 64 + unsigned int dbgext$l_status; + unsigned int dbgext$l_flags; + unsigned int dbgext$l_print_routine; + unsigned int dbgext$l_evnt_code; + unsigned int dbgext$l_evnt_name; + unsigned int dbgext$l_evnt_entry; + unsigned int dbgext$l_task_value; + unsigned int dbgext$l_task_number; + unsigned int dbgext$l_ada_flags; + unsigned int dbgext$l_stop_value; +#define dbgext$l_priority dbgext$l_stop_value; +#define dbgext$l_symb_addr dbgext$l_stop_value; +#define dbgext$l_time_slice dbgext$l_stop_value; + unsigned int dbgext$l_active_registers; +}; + +#pragma pointer_size save +#pragma pointer_size 32 + +/* Pthread handler. */ +static int (*dbgext_func) (struct dbgext_control_block *blk); + +#pragma pointer_size restore + +/* Set to 1 if thread-aware. */ +static int has_threads; + +/* Current thread. */ +static pthread_t selected_thread; +static pthreadDebugId_t selected_id; + +/* Internal debugging flags. */ +struct debug_flag +{ + /* Name of the flag (as a string descriptor). */ + const struct dsc$descriptor_s name; + /* Value. */ + int val; +}; + +/* Macro to define a debugging flag. */ +#define DEBUG_FLAG_ENTRY(str) \ + { { sizeof (str) - 1, DSC$K_DTYPE_T, DSC$K_CLASS_S, str }, 0} + +static struct debug_flag debug_flags[] = +{ + /* Disp packets exchanged with gdb. */ + DEBUG_FLAG_ENTRY("packets"), +#define trace_pkt (debug_flags[0].val) + /* Display entry point informations. */ + DEBUG_FLAG_ENTRY("entry"), +#define trace_entry (debug_flags[1].val) + /* Be verbose about exceptions. */ + DEBUG_FLAG_ENTRY("excp"), +#define trace_excp (debug_flags[2].val) + /* Be verbose about unwinding. */ + DEBUG_FLAG_ENTRY("unwind"), +#define trace_unwind (debug_flags[3].val) + /* Display image at startup. */ + DEBUG_FLAG_ENTRY("images"), +#define trace_images (debug_flags[4].val) + /* Display pthread_debug info. */ + DEBUG_FLAG_ENTRY("pthreaddbg") +#define trace_pthreaddbg (debug_flags[5].val) +}; + +#define NBR_DEBUG_FLAGS (sizeof (debug_flags) / sizeof (debug_flags[0])) + +/* Connect inet device I/O channel. */ +static unsigned short conn_channel; + +/* Widely used hex digit to ascii. */ +static const char hex[] = "0123456789abcdef"; + +/* Socket characteristics. Apparently, there are no declaration for it in + standard headers. */ +struct sockchar +{ + unsigned short prot; + unsigned char type; + unsigned char af; +}; + +/* Chain of images loaded. */ +extern IMCB* ctl$gl_imglstptr; + +/* IA64 integer register representation. */ +union ia64_ireg +{ + unsigned __int64 v; + unsigned char b[8]; +}; + +/* IA64 register numbers, as defined by ia64-tdep.h. */ +#define IA64_GR0_REGNUM 0 +#define IA64_GR32_REGNUM (IA64_GR0_REGNUM + 32) + +/* Floating point registers; 128 82-bit wide registers. */ +#define IA64_FR0_REGNUM 128 + +/* Predicate registers; There are 64 of these one bit registers. It'd + be more convenient (implementation-wise) to use a single 64 bit + word with all of these register in them. Note that there's also a + IA64_PR_REGNUM below which contains all the bits and is used for + communicating the actual values to the target. */ +#define IA64_PR0_REGNUM 256 + +/* Branch registers: 8 64-bit registers for holding branch targets. */ +#define IA64_BR0_REGNUM 320 + +/* Virtual frame pointer; this matches IA64_FRAME_POINTER_REGNUM in + gcc/config/ia64/ia64.h. */ +#define IA64_VFP_REGNUM 328 + +/* Virtual return address pointer; this matches + IA64_RETURN_ADDRESS_POINTER_REGNUM in gcc/config/ia64/ia64.h. */ +#define IA64_VRAP_REGNUM 329 + +/* Predicate registers: There are 64 of these 1-bit registers. We + define a single register which is used to communicate these values + to/from the target. We will somehow contrive to make it appear + that IA64_PR0_REGNUM thru IA64_PR63_REGNUM hold the actual values. */ +#define IA64_PR_REGNUM 330 + +/* Instruction pointer: 64 bits wide. */ +#define IA64_IP_REGNUM 331 + +/* Process Status Register. */ +#define IA64_PSR_REGNUM 332 + +/* Current Frame Marker (raw form may be the cr.ifs). */ +#define IA64_CFM_REGNUM 333 + +/* Application registers; 128 64-bit wide registers possible, but some + of them are reserved. */ +#define IA64_AR0_REGNUM 334 +#define IA64_KR0_REGNUM (IA64_AR0_REGNUM + 0) +#define IA64_KR7_REGNUM (IA64_KR0_REGNUM + 7) + +#define IA64_RSC_REGNUM (IA64_AR0_REGNUM + 16) +#define IA64_BSP_REGNUM (IA64_AR0_REGNUM + 17) +#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM + 18) +#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM + 19) +#define IA64_FCR_REGNUM (IA64_AR0_REGNUM + 21) +#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM + 24) +#define IA64_CSD_REGNUM (IA64_AR0_REGNUM + 25) +#define IA64_SSD_REGNUM (IA64_AR0_REGNUM + 26) +#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM + 27) +#define IA64_FSR_REGNUM (IA64_AR0_REGNUM + 28) +#define IA64_FIR_REGNUM (IA64_AR0_REGNUM + 29) +#define IA64_FDR_REGNUM (IA64_AR0_REGNUM + 30) +#define IA64_CCV_REGNUM (IA64_AR0_REGNUM + 32) +#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM + 36) +#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM + 40) +#define IA64_ITC_REGNUM (IA64_AR0_REGNUM + 44) +#define IA64_PFS_REGNUM (IA64_AR0_REGNUM + 64) +#define IA64_LC_REGNUM (IA64_AR0_REGNUM + 65) +#define IA64_EC_REGNUM (IA64_AR0_REGNUM + 66) + +/* NAT (Not A Thing) Bits for the general registers; there are 128 of + these. */ +#define IA64_NAT0_REGNUM 462 + +/* Process registers when a condition is caught. */ +struct ia64_all_regs +{ + union ia64_ireg gr[32]; + union ia64_ireg br[8]; + union ia64_ireg ip; + union ia64_ireg psr; + union ia64_ireg bsp; + union ia64_ireg cfm; + union ia64_ireg pfs; + union ia64_ireg pr; +}; + +static struct ia64_all_regs excp_regs; +static struct ia64_all_regs sel_regs; +static pthread_t sel_regs_pthread; + +/* IO channel for the terminal. */ +static unsigned short term_chan; + +/* Output buffer and length. */ +static char term_buf[128]; +static int term_buf_len; + +/* Buffer for communication with gdb. */ +static unsigned char gdb_buf[sizeof (struct ia64_all_regs) * 2 + 64]; +static unsigned int gdb_blen; + +/* Previous primary handler. */ +static void *prevhnd; + +/* Entry point address and bundle. */ +static unsigned __int64 entry_pc; +static unsigned char entry_saved[16]; + +/* Write on the terminal. */ + +static void +term_raw_write (const char *str, unsigned int len) +{ + unsigned short status; + struct _iosb iosb; + + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + term_chan, /* I/O channel. */ + IO$_WRITEVBLK, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + (char *)str, /* P1 - buffer address. */ + len, /* P2 - buffer length. */ + 0, 0, 0, 0); + + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); +} + +/* Flush ther term buffer. */ + +static void +term_flush (void) +{ + if (term_buf_len != 0) + { + term_raw_write (term_buf, term_buf_len); + term_buf_len = 0; + } +} + +/* Write a single character, without translation. */ + +static void +term_raw_putchar (char c) +{ + if (term_buf_len == sizeof (term_buf)) + term_flush (); + term_buf[term_buf_len++] = c; +} + +/* Write character C. Translate '\n' to '\n\r'. */ + +static void +term_putc (char c) +{ + if (c < 32) + switch (c) + { + case '\r': + case '\n': + break; + default: + c = '.'; + break; + } + term_raw_putchar (c); + if (c == '\n') + { + term_raw_putchar ('\r'); + term_flush (); + } +} + +/* Write a C string. */ + +static void +term_puts (const char *str) +{ + while (*str) + term_putc (*str++); +} + +/* Write LEN bytes from STR. */ + +static void +term_write (const char *str, unsigned int len) +{ + for (; len > 0; len--) + term_putc (*str++); +} + +/* Write using FAO formatting. */ + +static void +term_fao (const char *str, unsigned int str_len, ...) +{ + int cnt; + va_list vargs; + int i; + __int64 *args; + int status; + struct dsc$descriptor_s dstr = + { str_len, DSC$K_DTYPE_T, DSC$K_CLASS_S, (__char_ptr32)str }; + char buf[128]; + $DESCRIPTOR (buf_desc, buf); + + va_start (vargs, str_len); + va_count (cnt); + args = (__int64 *) __ALLOCA (cnt * sizeof (__int64)); + cnt -= 2; + for (i = 0; i < cnt; i++) + args[i] = va_arg (vargs, __int64); + + status = sys$faol_64 (&dstr, &buf_desc.dsc$w_length, &buf_desc, args); + if (status & 1) + { + /* FAO !/ already insert a line feed. */ + for (i = 0; i < buf_desc.dsc$w_length; i++) + { + term_raw_putchar (buf[i]); + if (buf[i] == '\n') + term_flush (); + } + } + + va_end (vargs); +} + +#define TERM_FAO(STR, ...) term_fao (STR, sizeof (STR) - 1, __VA_ARGS__) + +/* New line. */ + +static void +term_putnl (void) +{ + term_putc ('\n'); +} + +/* Initialize terminal. */ + +static void +term_init (void) +{ + unsigned int status,i; + unsigned short len; + char resstring[LNM$C_NAMLENGTH]; + static const $DESCRIPTOR (tabdesc, "LNM$FILE_DEV"); + static const $DESCRIPTOR (logdesc, "SYS$OUTPUT"); + $DESCRIPTOR (term_desc, resstring); + ILE3 item_lst[2]; + + item_lst[0].ile3$w_length = LNM$C_NAMLENGTH; + item_lst[0].ile3$w_code = LNM$_STRING; + item_lst[0].ile3$ps_bufaddr = resstring; + item_lst[0].ile3$ps_retlen_addr = &len; + item_lst[1].ile3$w_length = 0; + item_lst[1].ile3$w_code = 0; + + /* Translate the logical name. */ + status = SYS$TRNLNM (0, /* Attr of the logical name. */ + (void *) &tabdesc, /* Logical name table. */ + (void *) &logdesc, /* Logical name. */ + 0, /* Access mode. */ + item_lst); /* Item list. */ + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + + term_desc.dsc$w_length = len; + + /* Examine 4-byte header. Skip escape sequence. */ + if (resstring[0] == 0x1B) + { + term_desc.dsc$w_length -= 4; + term_desc.dsc$a_pointer += 4; + } + + /* Assign a channel. */ + status = sys$assign (&term_desc, /* Device name. */ + &term_chan, /* I/O channel. */ + 0, /* Access mode. */ + 0); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); +} + +/* Convert from native endianness to network endianness (and vice-versa). */ + +static unsigned int +wordswap (unsigned int v) +{ + return ((v & 0xff) << 8) | ((v >> 8) & 0xff); +} + +/* Initialize the socket connection, and wait for a client. */ + +static void +sock_init (void) +{ + struct _iosb iosb; + unsigned int status; + + /* Listen channel and characteristics. */ + unsigned short listen_channel; + struct sockchar listen_sockchar; + + /* Client address. */ + unsigned short cli_addrlen; + struct sockaddr_in cli_addr; + ILE3 cli_itemlst; + + /* Our address. */ + struct sockaddr_in serv_addr; + ILE2 serv_itemlst; + + /* Reuseaddr option value (on). */ + int optval = 1; + ILE2 sockopt_itemlst; + ILE2 reuseaddr_itemlst; + + /* TCP/IP network pseudodevice. */ + static const $DESCRIPTOR (inet_device, "TCPIP$DEVICE:"); + + /* Initialize socket characteristics. */ + listen_sockchar.prot = TCPIP$C_TCP; + listen_sockchar.type = TCPIP$C_STREAM; + listen_sockchar.af = TCPIP$C_AF_INET; + + /* Assign I/O channels to network device. */ + status = sys$assign ((void *) &inet_device, &listen_channel, 0, 0); + if (status & STS$M_SUCCESS) + status = sys$assign ((void *) &inet_device, &conn_channel, 0, 0); + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to assign I/O channel(s)\n"); + LIB$SIGNAL (status); + } + + /* Create a listen socket. */ + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_SETMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + &listen_sockchar, /* P1 - socket characteristics. */ + 0, 0, 0, 0, 0); + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to create socket\n"); + LIB$SIGNAL (status); + } + + /* Set reuse address option. */ + /* Initialize reuseaddr's item-list element. */ + reuseaddr_itemlst.ile2$w_length = sizeof (optval); + reuseaddr_itemlst.ile2$w_code = TCPIP$C_REUSEADDR; + reuseaddr_itemlst.ile2$ps_bufaddr = &optval; + + /* Initialize setsockopt's item-list descriptor. */ + sockopt_itemlst.ile2$w_length = sizeof (reuseaddr_itemlst); + sockopt_itemlst.ile2$w_code = TCPIP$C_SOCKOPT; + sockopt_itemlst.ile2$ps_bufaddr = &reuseaddr_itemlst; + + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_SETMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + 0, /* P3. */ + 0, /* P4. */ + (__int64) &sockopt_itemlst, /* P5 - socket options. */ + 0); + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to set socket option\n"); + LIB$SIGNAL (status); + } + + /* Bind server's ip address and port number to listen socket. */ + /* Initialize server's socket address structure. */ + ots$fill (&serv_addr, sizeof (serv_addr), 0); + serv_addr.sin_family = TCPIP$C_AF_INET; + serv_addr.sin_port = wordswap (serv_port); + serv_addr.sin_addr.s_addr = TCPIP$C_INADDR_ANY; + + /* Initialize server's item-list descriptor. */ + serv_itemlst.ile2$w_length = sizeof (serv_addr); + serv_itemlst.ile2$w_code = TCPIP$C_SOCK_NAME; + serv_itemlst.ile2$ps_bufaddr = &serv_addr; + + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_SETMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + (__int64) &serv_itemlst, /* P3 - local socket name. */ + 0, 0, 0); + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to bind socket\n"); + LIB$SIGNAL (status); + } + + /* Set socket as a listen socket. */ + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_SETMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + 0, /* P3. */ + 1, /* P4 - connection backlog. */ + 0, 0); + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to set socket passive\n"); + LIB$SIGNAL (status); + } + + /* Accept connection from a client. */ + TERM_FAO ("Waiting for a client connection on port: !ZW!/", + wordswap (serv_addr.sin_port)); + + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + listen_channel, /* I/O channel. */ + IO$_ACCESS|IO$M_ACCEPT, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + 0, /* P3. */ + (__int64) &conn_channel, /* P4 - I/O channel for conn. */ + 0, 0); + + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to accept client connection\n"); + LIB$SIGNAL (status); + } + + /* Log client connection request. */ + cli_itemlst.ile3$w_length = sizeof (cli_addr); + cli_itemlst.ile3$w_code = TCPIP$C_SOCK_NAME; + cli_itemlst.ile3$ps_bufaddr = &cli_addr; + cli_itemlst.ile3$ps_retlen_addr = &cli_addrlen; + ots$fill (&cli_addr, sizeof(cli_addr), 0); + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + conn_channel, /* I/O channel. */ + IO$_SENSEMODE, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, /* P1. */ + 0, /* P2. */ + 0, /* P3. */ + (__int64) &cli_itemlst, /* P4 - peer socket name. */ + 0, 0); + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to get client name\n"); + LIB$SIGNAL (status); + } + + TERM_FAO ("Accepted connection from host: !UB.!UB,!UB.!UB, port: !UW!/", + (cli_addr.sin_addr.s_addr >> 0) & 0xff, + (cli_addr.sin_addr.s_addr >> 8) & 0xff, + (cli_addr.sin_addr.s_addr >> 16) & 0xff, + (cli_addr.sin_addr.s_addr >> 24) & 0xff, + wordswap (cli_addr.sin_port)); +} + +/* Close the socket. */ + +static void +sock_close (void) +{ + struct _iosb iosb; + unsigned int status; + + /* Close socket. */ + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + conn_channel, /* I/O channel. */ + IO$_DEACCESS, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + 0, 0, 0, 0, 0, 0); + + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to close socket\n"); + LIB$SIGNAL (status); + } + + /* Deassign I/O channel to network device. */ + status = sys$dassgn (conn_channel); + + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to deassign I/O channel\n"); + LIB$SIGNAL (status); + } +} + +/* Mark a page as R/W. Return old rights. */ + +static unsigned int +page_set_rw (unsigned __int64 startva, unsigned __int64 len, + unsigned int *oldprot) +{ + unsigned int status; + unsigned __int64 retva; + unsigned __int64 retlen; + + status = SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, PRT$C_UW, + (void *)&retva, &retlen, oldprot); + return status; +} + +/* Restore page rights. */ + +static void +page_restore_rw (unsigned __int64 startva, unsigned __int64 len, + unsigned int prot) +{ + unsigned int status; + unsigned __int64 retva; + unsigned __int64 retlen; + unsigned int oldprot; + + status = SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, prot, + (void *)&retva, &retlen, &oldprot); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); +} + +/* Get the TEB (thread environment block). */ + +static pthread_t +get_teb (void) +{ + return (pthread_t)__getReg (_IA64_REG_TP); +} + +/* Enable thread scheduling if VAL is true. */ + +static unsigned int +set_thread_scheduling (int val) +{ + struct dbgext_control_block blk; + unsigned int status; + + if (!dbgext_func) + return 0; + + blk.dbgext$w_function_code = DBGEXT$K_STOP_ALL_OTHER_TASKS; + blk.dbgext$w_facility_id = CMA$_FACILITY; + blk.dbgext$l_stop_value = val; + + status = dbgext_func (&blk); + if (!(status & STS$M_SUCCESS)) + { + TERM_FAO ("set_thread_scheduling error, val=!SL, status=!XL!/", + val, blk.dbgext$l_status); + lib$signal (status); + } + + return blk.dbgext$l_stop_value; +} + +/* Get next thead (after THR). Start with 0. */ + +static unsigned int +thread_next (unsigned int thr) +{ + struct dbgext_control_block blk; + unsigned int status; + + if (!dbgext_func) + return 0; + + blk.dbgext$w_function_code = DBGEXT$K_NEXT_TASK; + blk.dbgext$w_facility_id = CMA$_FACILITY; + blk.dbgext$l_ada_flags = 0; + blk.dbgext$l_task_value = thr; + + status = dbgext_func (&blk); + if (!(status & STS$M_SUCCESS)) + lib$signal (status); + + return blk.dbgext$l_task_value; +} + +/* Pthread Debug callbacks. */ + +static int +read_callback (pthreadDebugClient_t context, + pthreadDebugTargetAddr_t addr, + pthreadDebugAddr_t buf, + size_t size) +{ + if (trace_pthreaddbg) + TERM_FAO ("read_callback (!XH, !XH, !SL)!/", addr, buf, size); + ots$move (buf, size, addr); + return 0; +} + +static int +write_callback (pthreadDebugClient_t context, + pthreadDebugTargetAddr_t addr, + pthreadDebugLongConstAddr_t buf, + size_t size) +{ + if (trace_pthreaddbg) + TERM_FAO ("write_callback (!XH, !XH, !SL)!/", addr, buf, size); + ots$move (addr, size, buf); + return 0; +} + +static int +suspend_callback (pthreadDebugClient_t context) +{ + /* Always suspended. */ + return 0; +} + +static int +resume_callback (pthreadDebugClient_t context) +{ + /* So no need to resume. */ + return 0; +} + +static int +kthdinfo_callback (pthreadDebugClient_t context, + pthreadDebugKId_t kid, + pthreadDebugKThreadInfo_p thread_info) +{ + if (trace_pthreaddbg) + term_puts ("kthinfo_callback"); + return ENOSYS; +} + +static int +hold_callback (pthreadDebugClient_t context, + pthreadDebugKId_t kid) +{ + if (trace_pthreaddbg) + term_puts ("hold_callback"); + return ENOSYS; +} + +static int +unhold_callback (pthreadDebugClient_t context, + pthreadDebugKId_t kid) +{ + if (trace_pthreaddbg) + term_puts ("unhold_callback"); + return ENOSYS; +} + +static int +getfreg_callback (pthreadDebugClient_t context, + pthreadDebugFregs_t *reg, + pthreadDebugKId_t kid) +{ + if (trace_pthreaddbg) + term_puts ("getfreg_callback"); + return ENOSYS; +} + +static int +setfreg_callback (pthreadDebugClient_t context, + const pthreadDebugFregs_t *reg, + pthreadDebugKId_t kid) +{ + if (trace_pthreaddbg) + term_puts ("setfreg_callback"); + return ENOSYS; +} + +static int +getreg_callback (pthreadDebugClient_t context, + pthreadDebugRegs_t *reg, + pthreadDebugKId_t kid) +{ + if (trace_pthreaddbg) + term_puts ("getreg_callback"); + return ENOSYS; +} + +static int +setreg_callback (pthreadDebugClient_t context, + const pthreadDebugRegs_t *reg, + pthreadDebugKId_t kid) +{ + if (trace_pthreaddbg) + term_puts ("setreg_callback"); + return ENOSYS; +} + +static int +output_callback (pthreadDebugClient_t context, + pthreadDebugConstString_t line) +{ + term_puts (line); + term_putnl (); + return 0; +} + +static int +error_callback (pthreadDebugClient_t context, + pthreadDebugConstString_t line) +{ + term_puts (line); + term_putnl (); + return 0; +} + +static pthreadDebugAddr_t +malloc_callback (pthreadDebugClient_t caller_context, size_t size) +{ + unsigned int status; + unsigned int res; + int len; + + len = size + 16; + status = lib$get_vm (&len, &res, 0); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + if (trace_pthreaddbg) + TERM_FAO ("malloc_callback (!UL) -> !XA!/", size, res); + *(unsigned int *)res = len; + return (char *)res + 16; +} + +static void +free_callback (pthreadDebugClient_t caller_context, pthreadDebugAddr_t address) +{ + unsigned int status; + unsigned int res; + int len; + + res = (unsigned int)address - 16; + len = *(unsigned int *)res; + if (trace_pthreaddbg) + TERM_FAO ("free_callback (!XA)!/", address); + status = lib$free_vm (&len, &res, 0); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); +} + +static int +speckthd_callback (pthreadDebugClient_t caller_context, + pthreadDebugSpecialType_t type, + pthreadDebugKId_t *kernel_tid) +{ + return ENOTSUP; +} + +static pthreadDebugCallbacks_t pthread_debug_callbacks = { + PTHREAD_DEBUG_VERSION, + read_callback, + write_callback, + suspend_callback, + resume_callback, + kthdinfo_callback, + hold_callback, + unhold_callback, + getfreg_callback, + setfreg_callback, + getreg_callback, + setreg_callback, + output_callback, + error_callback, + malloc_callback, + free_callback, + speckthd_callback +}; + +/* Name of the pthread shared library. */ +static const $DESCRIPTOR (pthread_rtl_desc, "PTHREAD$RTL"); + +/* List of symbols to extract from pthread debug library. */ +struct pthread_debug_entry +{ + const unsigned int namelen; + const __char_ptr32 name; + __void_ptr32 func; +}; + +#define DEBUG_ENTRY(str) { sizeof(str) - 1, str, 0 } + +static struct pthread_debug_entry pthread_debug_entries[] = { + DEBUG_ENTRY("pthreadDebugContextInit"), + DEBUG_ENTRY("pthreadDebugThdSeqInit"), + DEBUG_ENTRY("pthreadDebugThdSeqNext"), + DEBUG_ENTRY("pthreadDebugThdSeqDestroy"), + DEBUG_ENTRY("pthreadDebugThdGetInfo"), + DEBUG_ENTRY("pthreadDebugThdGetInfoAddr"), + DEBUG_ENTRY("pthreadDebugThdGetReg"), + DEBUG_ENTRY("pthreadDebugCmd") +}; + +/* Pthread debug context. */ +static pthreadDebugContext_t debug_context; + +/* Wrapper around pthread debug entry points. */ + +static int +pthread_debug_thd_seq_init (pthreadDebugId_t *id) +{ + return ((int (*)())pthread_debug_entries[1].func) + (debug_context, id); +} + +static int +pthread_debug_thd_seq_next (pthreadDebugId_t *id) +{ + return ((int (*)())pthread_debug_entries[2].func) + (debug_context, id); +} + +static int +pthread_debug_thd_seq_destroy (void) +{ + return ((int (*)())pthread_debug_entries[3].func) + (debug_context); +} + +static int +pthread_debug_thd_get_info (pthreadDebugId_t id, + pthreadDebugThreadInfo_t *info) +{ + return ((int (*)())pthread_debug_entries[4].func) + (debug_context, id, info); +} + +static int +pthread_debug_thd_get_info_addr (pthread_t thr, + pthreadDebugThreadInfo_t *info) +{ + return ((int (*)())pthread_debug_entries[5].func) + (debug_context, thr, info); +} + +static int +pthread_debug_thd_get_reg (pthreadDebugId_t thr, + pthreadDebugRegs_t *regs) +{ + return ((int (*)())pthread_debug_entries[6].func) + (debug_context, thr, regs); +} + +static int +stub_pthread_debug_cmd (const char *cmd) +{ + return ((int (*)())pthread_debug_entries[7].func) + (debug_context, cmd); +} + +/* Show all the threads. */ + +static void +threads_show (void) +{ + pthreadDebugId_t id; + pthreadDebugThreadInfo_t info; + int res; + + res = pthread_debug_thd_seq_init (&id); + if (res != 0) + { + TERM_FAO ("seq init failed, res=!SL!/", res); + return; + } + while (1) + { + if (pthread_debug_thd_get_info (id, &info) != 0) + { + TERM_FAO ("thd_get_info !SL failed!/", id); + break; + } + if (pthread_debug_thd_seq_next (&id) != 0) + break; + } + pthread_debug_thd_seq_destroy (); +} + +/* Initialize pthread support. */ + +static void +threads_init (void) +{ + static const $DESCRIPTOR (dbgext_desc, "PTHREAD$DBGEXT"); + static const $DESCRIPTOR (pthread_debug_desc, "PTHREAD$DBGSHR"); + static const $DESCRIPTOR (dbgsymtable_desc, "PTHREAD_DBG_SYMTABLE"); + int pthread_dbgext; + int status; + void *dbg_symtable; + int i; + void *caller_context = 0; + + status = lib$find_image_symbol + ((void *) &pthread_rtl_desc, (void *) &dbgext_desc, + (int *) &dbgext_func); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + + status = lib$find_image_symbol + ((void *) &pthread_rtl_desc, (void *) &dbgsymtable_desc, + (int *) &dbg_symtable); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + + /* Find entry points in pthread_debug. */ + for (i = 0; + i < sizeof (pthread_debug_entries) / sizeof (pthread_debug_entries[0]); + i++) + { + struct dsc$descriptor_s sym = + { pthread_debug_entries[i].namelen, + DSC$K_DTYPE_T, DSC$K_CLASS_S, + pthread_debug_entries[i].name }; + status = lib$find_image_symbol + ((void *) &pthread_debug_desc, (void *) &sym, + (int *) &pthread_debug_entries[i].func); + if (!(status & STS$M_SUCCESS)) + lib$signal (status); + } + + if (trace_pthreaddbg) + TERM_FAO ("debug symtable: !XH!/", dbg_symtable); + status = ((int (*)()) pthread_debug_entries[0].func) + (&caller_context, &pthread_debug_callbacks, dbg_symtable, &debug_context); + if (status != 0) + TERM_FAO ("cannot initialize pthread_debug: !UL!/", status); + TERM_FAO ("pthread debug done!/", 0); +} + +/* Convert an hexadecimal character to a nibble. Return -1 in case of + error. */ + +static int +hex2nibble (unsigned char h) +{ + if (h >= '0' && h <= '9') + return h - '0'; + if (h >= 'A' && h <= 'F') + return h - 'A' + 10; + if (h >= 'a' && h <= 'f') + return h - 'a' + 10; + return -1; +} + +/* Convert an hexadecimal 2 character string to a byte. Return -1 in case + of error. */ + +static int +hex2byte (const unsigned char *p) +{ + int h, l; + + h = hex2nibble (p[0]); + l = hex2nibble (p[1]); + if (h == -1 || l == -1) + return -1; + return (h << 4) | l; +} + +/* Convert a byte V to a 2 character strings P. */ + +static void +byte2hex (unsigned char *p, unsigned char v) +{ + p[0] = hex[v >> 4]; + p[1] = hex[v & 0xf]; +} + +/* Convert a quadword V to a 16 character strings P. */ + +static void +quad2hex (unsigned char *p, unsigned __int64 v) +{ + int i; + for (i = 0; i < 16; i++) + { + p[i] = hex[v >> 60]; + v <<= 4; + } +} + +static void +long2pkt (unsigned int v) +{ + int i; + + for (i = 0; i < 8; i++) + { + gdb_buf[gdb_blen + i] = hex[(v >> 28) & 0x0f]; + v <<= 4; + } + gdb_blen += 8; +} + +/* Generate an error packet. */ + +static void +packet_error (unsigned int err) +{ + gdb_buf[1] = 'E'; + byte2hex (gdb_buf + 2, err); + gdb_blen = 4; +} + +/* Generate an OK packet. */ + +static void +packet_ok (void) +{ + gdb_buf[1] = 'O'; + gdb_buf[2] = 'K'; + gdb_blen = 3; +} + +/* Append a register to the packet. */ + +static void +ireg2pkt (const unsigned char *p) +{ + int i; + + for (i = 0; i < 8; i++) + { + byte2hex (gdb_buf + gdb_blen, p[i]); + gdb_blen += 2; + } +} + +/* Append a C string (ASCIZ) to the packet. */ + +static void +str2pkt (const char *str) +{ + while (*str) + gdb_buf[gdb_blen++] = *str++; +} + +/* Extract a number fro the packet. */ + +static unsigned __int64 +pkt2val (const unsigned char *pkt, unsigned int *pos) +{ + unsigned __int64 res = 0; + unsigned int i; + + while (1) + { + int r = hex2nibble (pkt[*pos]); + + if (r < 0) + return res; + res = (res << 4) | r; + (*pos)++; + } +} + +/* Append LEN bytes from B to the current gdb packet (encode in binary). */ + +static void +mem2bin (const unsigned char *b, unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; i++) + switch (b[i]) + { + case '#': + case '$': + case '}': + case '*': + case 0: + gdb_buf[gdb_blen++] = '}'; + gdb_buf[gdb_blen++] = b[i] ^ 0x20; + break; + default: + gdb_buf[gdb_blen++] = b[i]; + break; + } +} + +/* Append LEN bytes from B to the current gdb packet (encode in hex). */ + +static void +mem2hex (const unsigned char *b, unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; i++) + { + byte2hex (gdb_buf + gdb_blen, b[i]); + gdb_blen += 2; + } +} + +/* Handle the 'q' packet. */ + +static void +handle_q_packet (const unsigned char *pkt, unsigned int pktlen) +{ + /* For qfThreadInfo and qsThreadInfo. */ + static unsigned int first_thread; + static unsigned int last_thread; + + static const char xfer_uib[] = "qXfer:uib:read:"; +#define XFER_UIB_LEN (sizeof (xfer_uib) - 1) + static const char qfthreadinfo[] = "qfThreadInfo"; +#define QFTHREADINFO_LEN (sizeof (qfthreadinfo) - 1) + static const char qsthreadinfo[] = "qsThreadInfo"; +#define QSTHREADINFO_LEN (sizeof (qsthreadinfo) - 1) + static const char qthreadextrainfo[] = "qThreadExtraInfo,"; +#define QTHREADEXTRAINFO_LEN (sizeof (qthreadextrainfo) - 1) + static const char qsupported[] = "qSupported:"; +#define QSUPPORTED_LEN (sizeof (qsupported) - 1) + + if (pktlen == 2 && pkt[1] == 'C') + { + /* Current thread. */ + gdb_buf[0] = '$'; + gdb_buf[1] = 'Q'; + gdb_buf[2] = 'C'; + gdb_blen = 3; + if (has_threads) + long2pkt ((unsigned long) get_teb ()); + return; + } + else if (pktlen > XFER_UIB_LEN + && ots$strcmp_eql (pkt, XFER_UIB_LEN, xfer_uib, XFER_UIB_LEN)) + { + /* Get unwind information block. */ + unsigned __int64 pc; + unsigned int pos = XFER_UIB_LEN; + unsigned int off; + unsigned int len; + union + { + unsigned char bytes[32]; + struct + { + unsigned __int64 code_start_va; + unsigned __int64 code_end_va; + unsigned __int64 uib_start_va; + unsigned __int64 gp_value; + } data; + } uei; + int res; + int i; + + packet_error (0); + + pc = pkt2val (pkt, &pos); + if (pkt[pos] != ':') + return; + pos++; + off = pkt2val (pkt, &pos); + if (pkt[pos] != ',' || off != 0) + return; + pos++; + len = pkt2val (pkt, &pos); + if (pkt[pos] != '#' || len != 0x20) + return; + + res = SYS$GET_UNWIND_ENTRY_INFO (pc, &uei.data, 0); + if (res == SS$_NODATA || res != SS$_NORMAL) + ots$fill (uei.bytes, sizeof (uei.bytes), 0); + + if (trace_unwind) + { + TERM_FAO ("Unwind request for !XH, status=!XL, uib=!XQ, GP=!XQ!/", + pc, res, uei.data.uib_start_va, uei.data.gp_value); + } + + gdb_buf[0] = '$'; + gdb_buf[1] = 'l'; + gdb_blen = 2; + mem2bin (uei.bytes, sizeof (uei.bytes)); + } + else if (pktlen == QFTHREADINFO_LEN + && ots$strcmp_eql (pkt, QFTHREADINFO_LEN, + qfthreadinfo, QFTHREADINFO_LEN)) + { + /* Get first thread(s). */ + gdb_buf[0] = '$'; + gdb_buf[1] = 'm'; + gdb_blen = 2; + + if (!has_threads) + { + gdb_buf[1] = 'l'; + return; + } + first_thread = thread_next (0); + last_thread = first_thread; + long2pkt (first_thread); + } + else if (pktlen == QSTHREADINFO_LEN + && ots$strcmp_eql (pkt, QSTHREADINFO_LEN, + qsthreadinfo, QSTHREADINFO_LEN)) + { + /* Get subsequent threads. */ + gdb_buf[0] = '$'; + gdb_buf[1] = 'm'; + gdb_blen = 2; + while (dbgext_func) + { + unsigned int res; + res = thread_next (last_thread); + if (res == first_thread) + break; + if (gdb_blen > 2) + gdb_buf[gdb_blen++] = ','; + long2pkt (res); + last_thread = res; + if (gdb_blen > sizeof (gdb_buf) - 16) + break; + } + + if (gdb_blen == 2) + gdb_buf[1] = 'l'; + } + else if (pktlen > QTHREADEXTRAINFO_LEN + && ots$strcmp_eql (pkt, QTHREADEXTRAINFO_LEN, + qthreadextrainfo, QTHREADEXTRAINFO_LEN)) + { + /* Get extra info about a thread. */ + pthread_t thr; + unsigned int pos = QTHREADEXTRAINFO_LEN; + pthreadDebugThreadInfo_t info; + int res; + + packet_error (0); + if (!has_threads) + return; + + thr = (pthread_t) pkt2val (pkt, &pos); + if (pkt[pos] != '#') + return; + res = pthread_debug_thd_get_info_addr (thr, &info); + if (res != 0) + { + TERM_FAO ("qThreadExtraInfo (!XH) failed: !SL!/", thr, res); + return; + } + gdb_buf[0] = '$'; + gdb_blen = 1; + mem2hex ((const unsigned char *)"VMS-thread", 11); + } + else if (pktlen > QSUPPORTED_LEN + && ots$strcmp_eql (pkt, QSUPPORTED_LEN, + qsupported, QSUPPORTED_LEN)) + { + /* Get supported features. */ + pthread_t thr; + unsigned int pos = QSUPPORTED_LEN; + pthreadDebugThreadInfo_t info; + int res; + + /* Ignore gdb features. */ + gdb_buf[0] = '$'; + gdb_blen = 1; + + str2pkt ("qXfer:uib:read+"); + return; + } + else + { + if (trace_pkt) + { + term_puts ("unknown <: "); + term_write ((char *)pkt, pktlen); + term_putnl (); + } + return; + } +} + +/* Handle the 'v' packet. */ + +static int +handle_v_packet (const unsigned char *pkt, unsigned int pktlen) +{ + static const char vcontq[] = "vCont?"; +#define VCONTQ_LEN (sizeof (vcontq) - 1) + + if (pktlen == VCONTQ_LEN + && ots$strcmp_eql (pkt, VCONTQ_LEN, vcontq, VCONTQ_LEN)) + { + gdb_buf[0] = '$'; + gdb_blen = 1; + + str2pkt ("vCont;c;s"); + return 0; + } + else + { + if (trace_pkt) + { + term_puts ("unknown <: "); + term_write ((char *)pkt, pktlen); + term_putnl (); + } + return 0; + } +} + +/* Get regs for the selected thread. */ + +static struct ia64_all_regs * +get_selected_regs (void) +{ + pthreadDebugRegs_t regs; + int res; + + if (selected_thread == 0 || selected_thread == get_teb ()) + return &excp_regs; + + if (selected_thread == sel_regs_pthread) + return &sel_regs; + + /* Read registers. */ + res = pthread_debug_thd_get_reg (selected_id, ®s); + if (res != 0) + { + /* FIXME: return NULL ? */ + return &excp_regs; + } + sel_regs_pthread = selected_thread; + sel_regs.gr[1].v = regs.gp; + sel_regs.gr[4].v = regs.r4; + sel_regs.gr[5].v = regs.r5; + sel_regs.gr[6].v = regs.r6; + sel_regs.gr[7].v = regs.r7; + sel_regs.gr[12].v = regs.sp; + sel_regs.br[0].v = regs.rp; + sel_regs.br[1].v = regs.b1; + sel_regs.br[2].v = regs.b2; + sel_regs.br[3].v = regs.b3; + sel_regs.br[4].v = regs.b4; + sel_regs.br[5].v = regs.b5; + sel_regs.ip.v = regs.ip; + sel_regs.bsp.v = regs.bspstore; /* FIXME: it is correct ? */ + sel_regs.pfs.v = regs.pfs; + sel_regs.pr.v = regs.pr; + return &sel_regs; +} + +/* Create a status packet. */ + +static void +packet_status (void) +{ + gdb_blen = 0; + if (has_threads) + { + str2pkt ("$T05thread:"); + long2pkt ((unsigned long) get_teb ()); + gdb_buf[gdb_blen++] = ';'; + } + else + str2pkt ("$S05"); +} + +/* Return 1 to continue. */ + +static int +handle_packet (unsigned char *pkt, unsigned int len) +{ + unsigned int pos; + + /* By default, reply unsupported. */ + gdb_buf[0] = '$'; + gdb_blen = 1; + + pos = 1; + switch (pkt[0]) + { + case '?': + if (len == 1) + { + packet_status (); + return 0; + } + break; + case 'c': + if (len == 1) + { + /* Clear psr.ss. */ + excp_regs.psr.v &= ~(unsigned __int64)PSR$M_SS; + return 1; + } + else + packet_error (0); + break; + case 'g': + if (len == 1) + { + unsigned int i; + struct ia64_all_regs *regs = get_selected_regs (); + unsigned char *p = regs->gr[0].b; + + for (i = 0; i < 8 * 32; i++) + byte2hex (gdb_buf + 1 + 2 * i, p[i]); + gdb_blen += 2 * 8 * 32; + return 0; + } + break; + case 'H': + if (pkt[1] == 'g') + { + int res; + unsigned __int64 val; + pthreadDebugThreadInfo_t info; + + pos++; + val = pkt2val (pkt, &pos); + if (pos != len) + { + packet_error (0); + return 0; + } + if (val == 0) + { + /* Default one. */ + selected_thread = get_teb (); + selected_id = 0; + } + else if (!has_threads) + { + packet_error (0); + return 0; + } + else + { + res = pthread_debug_thd_get_info_addr ((pthread_t) val, &info); + if (res != 0) + { + TERM_FAO ("qThreadExtraInfo (!XH) failed: !SL!/", val, res); + packet_error (0); + return 0; + } + selected_thread = info.teb; + selected_id = info.sequence; + } + packet_ok (); + break; + } + else if (pkt[1] == 'c' + && ((pkt[2] == '-' && pkt[3] == '1' && len == 4) + || (pkt[2] == '0' && len == 3))) + { + /* Silently accept 'Hc0' and 'Hc-1'. */ + packet_ok (); + break; + } + else + { + packet_error (0); + return 0; + } + case 'k': + SYS$EXIT (SS$_NORMAL); + break; + case 'm': + { + unsigned __int64 addr; + unsigned __int64 paddr; + unsigned int l; + unsigned int i; + + addr = pkt2val (pkt, &pos); + if (pkt[pos] != ',') + { + packet_error (0); + return 0; + } + pos++; + l = pkt2val (pkt, &pos); + if (pkt[pos] != '#') + { + packet_error (0); + return 0; + } + + /* Check access. */ + i = l + (addr & VMS_PAGE_MASK); + paddr = addr & ~VMS_PAGE_MASK; + while (1) + { + if (__prober (paddr, 0) != 1) + { + packet_error (2); + return 0; + } + if (i < VMS_PAGE_SIZE) + break; + i -= VMS_PAGE_SIZE; + paddr += VMS_PAGE_SIZE; + } + + /* Transfer. */ + for (i = 0; i < l; i++) + byte2hex (gdb_buf + 1 + 2 * i, ((unsigned char *)addr)[i]); + gdb_blen += 2 * l; + } + break; + case 'M': + { + unsigned __int64 addr; + unsigned __int64 paddr; + unsigned int l; + unsigned int i; + unsigned int oldprot; + + addr = pkt2val (pkt, &pos); + if (pkt[pos] != ',') + { + packet_error (0); + return 0; + } + pos++; + l = pkt2val (pkt, &pos); + if (pkt[pos] != ':') + { + packet_error (0); + return 0; + } + pos++; + page_set_rw (addr, l, &oldprot); + + /* Check access. */ + i = l + (addr & VMS_PAGE_MASK); + paddr = addr & ~VMS_PAGE_MASK; + while (1) + { + if (__probew (paddr, 0) != 1) + { + page_restore_rw (addr, l, oldprot); + return 0; + } + if (i < VMS_PAGE_SIZE) + break; + i -= VMS_PAGE_SIZE; + paddr += VMS_PAGE_SIZE; + } + + /* Write. */ + for (i = 0; i < l; i++) + { + int v = hex2byte (pkt + pos); + pos += 2; + ((unsigned char *)addr)[i] = v; + } + + /* Sync caches. */ + for (i = 0; i < l; i += 15) + __fc (addr + i); + __fc (addr + l); + + page_restore_rw (addr, l, oldprot); + packet_ok (); + } + break; + case 'p': + { + unsigned int num = 0; + unsigned int i; + struct ia64_all_regs *regs = get_selected_regs (); + + num = pkt2val (pkt, &pos); + if (pos != len) + { + packet_error (0); + return 0; + } + + switch (num) + { + case IA64_IP_REGNUM: + ireg2pkt (regs->ip.b); + break; + case IA64_BR0_REGNUM: + ireg2pkt (regs->br[0].b); + break; + case IA64_PSR_REGNUM: + ireg2pkt (regs->psr.b); + break; + case IA64_BSP_REGNUM: + ireg2pkt (regs->bsp.b); + break; + case IA64_CFM_REGNUM: + ireg2pkt (regs->cfm.b); + break; + case IA64_PFS_REGNUM: + ireg2pkt (regs->pfs.b); + break; + case IA64_PR_REGNUM: + ireg2pkt (regs->pr.b); + break; + default: + TERM_FAO ("gdbserv: unhandled reg !UW!/", num); + packet_error (0); + return 0; + } + } + break; + case 'q': + handle_q_packet (pkt, len); + break; + case 's': + if (len == 1) + { + /* Set psr.ss. */ + excp_regs.psr.v |= (unsigned __int64)PSR$M_SS; + return 1; + } + else + packet_error (0); + break; + case 'T': + /* Thread status. */ + if (!has_threads) + { + packet_ok (); + break; + } + else + { + int res; + unsigned __int64 val; + unsigned int fthr, thr; + + val = pkt2val (pkt, &pos); + /* Default is error (but only after parsing is complete). */ + packet_error (0); + if (pos != len) + break; + + /* Follow the list. This makes a O(n2) algorithm, but we don't really + have the choice. Note that pthread_debug_thd_get_info_addr + doesn't look reliable. */ + fthr = thread_next (0); + thr = fthr; + do + { + if (val == thr) + { + packet_ok (); + break; + } + thr = thread_next (thr); + } + while (thr != fthr); + } + break; + case 'v': + return handle_v_packet (pkt, len); + break; + case 'V': + if (len > 3 && pkt[1] == 'M' && pkt[2] == 'S' && pkt[3] == ' ') + { + /* Temporary extension. */ + if (has_threads) + { + pkt[len] = 0; + stub_pthread_debug_cmd ((char *)pkt + 4); + packet_ok (); + } + else + packet_error (0); + } + break; + default: + if (trace_pkt) + { + term_puts ("unknown <: "); + term_write ((char *)pkt, len); + term_putnl (); + } + break; + } + return 0; +} + +/* Raw write to gdb. */ + +static void +sock_write (const unsigned char *buf, int len) +{ + struct _iosb iosb; + unsigned int status; + + /* Write data to connection. */ + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + conn_channel, /* I/O channel. */ + IO$_WRITEVBLK, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + (char *)buf, /* P1 - buffer address. */ + len, /* P2 - buffer length. */ + 0, 0, 0, 0); + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to write data to gdb\n"); + LIB$SIGNAL (status); + } +} + +/* Compute the cheksum and send the packet. */ + +static void +send_pkt (void) +{ + unsigned char chksum = 0; + unsigned int i; + + for (i = 1; i < gdb_blen; i++) + chksum += gdb_buf[i]; + + gdb_buf[gdb_blen] = '#'; + byte2hex (gdb_buf + gdb_blen + 1, chksum); + + sock_write (gdb_buf, gdb_blen + 3); + + if (trace_pkt > 1) + { + term_puts (">: "); + term_write ((char *)gdb_buf, gdb_blen + 3); + term_putnl (); + } +} + +/* Read and handle one command. Return 1 is execution must resume. */ + +static int +one_command (void) +{ + struct _iosb iosb; + unsigned int status; + unsigned int off; + unsigned int dollar_off = 0; + unsigned int sharp_off = 0; + unsigned int cmd_off; + unsigned int cmd_len; + + /* Wait for a packet. */ + while (1) + { + off = 0; + while (1) + { + /* Read data from connection. */ + status = sys$qiow (EFN$C_ENF, /* Event flag. */ + conn_channel, /* I/O channel. */ + IO$_READVBLK, /* I/O function code. */ + &iosb, /* I/O status block. */ + 0, /* Ast service routine. */ + 0, /* Ast parameter. */ + gdb_buf + off, /* P1 - buffer address. */ + sizeof (gdb_buf) - off, /* P2 - buffer leng. */ + 0, 0, 0, 0); + if (status & STS$M_SUCCESS) + status = iosb.iosb$w_status; + if (!(status & STS$M_SUCCESS)) + { + term_puts ("Failed to read data from connection\n" ); + LIB$SIGNAL (status); + } + +#ifdef RAW_DUMP + term_puts ("{: "); + term_write ((char *)gdb_buf + off, iosb.iosb$w_bcnt); + term_putnl (); +#endif + + gdb_blen = off + iosb.iosb$w_bcnt; + + if (off == 0) + { + /* Search for '$'. */ + for (dollar_off = 0; dollar_off < gdb_blen; dollar_off++) + if (gdb_buf[dollar_off] == '$') + break; + if (dollar_off >= gdb_blen) + { + /* Not found, discard the data. */ + off = 0; + continue; + } + /* Search for '#'. */ + for (sharp_off = dollar_off + 1; + sharp_off < gdb_blen; + sharp_off++) + if (gdb_buf[sharp_off] == '#') + break; + } + else if (sharp_off >= off) + { + /* Search for '#'. */ + for (; sharp_off < gdb_blen; sharp_off++) + if (gdb_buf[sharp_off] == '#') + break; + } + + /* Got packet with checksum. */ + if (sharp_off + 2 <= gdb_blen) + break; + + off = gdb_blen; + if (gdb_blen == sizeof (gdb_buf)) + { + /* Packet too large, discard. */ + off = 0; + } + } + + /* Validate and acknowledge a packet. */ + { + unsigned char chksum = 0; + unsigned int i; + int v; + + for (i = dollar_off + 1; i < sharp_off; i++) + chksum += gdb_buf[i]; + v = hex2byte (gdb_buf + sharp_off + 1); + if (v != chksum) + { + term_puts ("Discard bad checksum packet\n"); + continue; + } + else + { + sock_write ((const unsigned char *)"+", 1); + break; + } + } + } + + if (trace_pkt > 1) + { + term_puts ("<: "); + term_write ((char *)gdb_buf + dollar_off, sharp_off - dollar_off + 1); + term_putnl (); + } + + cmd_off = dollar_off + 1; + cmd_len = sharp_off - dollar_off - 1; + + if (handle_packet (gdb_buf + dollar_off + 1, sharp_off - dollar_off - 1) == 1) + return 1; + + send_pkt (); + return 0; +} + +/* Display the condition given by SIG64. */ + +static void +display_excp (struct chf64$signal_array *sig64, struct chf$mech_array *mech) +{ + unsigned int status; + char msg[160]; + unsigned short msglen; + $DESCRIPTOR (msg_desc, msg); + unsigned char outadr[4]; + + status = SYS$GETMSG (sig64->chf64$q_sig_name, &msglen, &msg_desc, 0, outadr); + if (status & STS$M_SUCCESS) + { + char msg2[160]; + unsigned short msg2len; + struct dsc$descriptor_s msg2_desc = + { sizeof (msg2), DSC$K_DTYPE_T, DSC$K_CLASS_S, msg2}; + msg_desc.dsc$w_length = msglen; + status = SYS$FAOL_64 (&msg_desc, &msg2len, &msg2_desc, + &sig64->chf64$q_sig_arg1); + if (status & STS$M_SUCCESS) + term_write (msg2, msg2len); + } + else + term_puts ("no message"); + term_putnl (); + + if (trace_excp > 1) + { + TERM_FAO (" Frame: !XH, Depth: !4SL, Esf: !XH!/", + mech->chf$q_mch_frame, mech->chf$q_mch_depth, + mech->chf$q_mch_esf_addr); + } +} + +/* Get all registers from current thread. */ + +static void +read_all_registers (struct chf$mech_array *mech) +{ + struct _intstk *intstk = + (struct _intstk *)mech->chf$q_mch_esf_addr; + struct chf64$signal_array *sig64 = + (struct chf64$signal_array *)mech->chf$ph_mch_sig64_addr; + unsigned int cnt = sig64->chf64$w_sig_arg_count; + unsigned __int64 pc = (&sig64->chf64$q_sig_name)[cnt - 2]; + + excp_regs.ip.v = pc; + excp_regs.psr.v = intstk->intstk$q_ipsr; + /* GDB and linux expects bsp to point after the current register frame. + Adjust. */ + { + unsigned __int64 bsp = intstk->intstk$q_bsp; + unsigned int sof = intstk->intstk$q_ifs & 0x7f; + unsigned int delta = ((bsp >> 3) & 0x3f) + sof; + excp_regs.bsp.v = bsp + ((sof + delta / 0x3f) << 3); + } + excp_regs.cfm.v = intstk->intstk$q_ifs & 0x3fffffffff; + excp_regs.pfs.v = intstk->intstk$q_pfs; + excp_regs.pr.v = intstk->intstk$q_preds; + excp_regs.gr[0].v = 0; + excp_regs.gr[1].v = intstk->intstk$q_gp; + excp_regs.gr[2].v = intstk->intstk$q_r2; + excp_regs.gr[3].v = intstk->intstk$q_r3; + excp_regs.gr[4].v = intstk->intstk$q_r4; + excp_regs.gr[5].v = intstk->intstk$q_r5; + excp_regs.gr[6].v = intstk->intstk$q_r6; + excp_regs.gr[7].v = intstk->intstk$q_r7; + excp_regs.gr[8].v = intstk->intstk$q_r8; + excp_regs.gr[9].v = intstk->intstk$q_r9; + excp_regs.gr[10].v = intstk->intstk$q_r10; + excp_regs.gr[11].v = intstk->intstk$q_r11; + excp_regs.gr[12].v = (unsigned __int64)intstk + intstk->intstk$l_stkalign; + excp_regs.gr[13].v = intstk->intstk$q_r13; + excp_regs.gr[14].v = intstk->intstk$q_r14; + excp_regs.gr[15].v = intstk->intstk$q_r15; + excp_regs.gr[16].v = intstk->intstk$q_r16; + excp_regs.gr[17].v = intstk->intstk$q_r17; + excp_regs.gr[18].v = intstk->intstk$q_r18; + excp_regs.gr[19].v = intstk->intstk$q_r19; + excp_regs.gr[20].v = intstk->intstk$q_r20; + excp_regs.gr[21].v = intstk->intstk$q_r21; + excp_regs.gr[22].v = intstk->intstk$q_r22; + excp_regs.gr[23].v = intstk->intstk$q_r23; + excp_regs.gr[24].v = intstk->intstk$q_r24; + excp_regs.gr[25].v = intstk->intstk$q_r25; + excp_regs.gr[26].v = intstk->intstk$q_r26; + excp_regs.gr[27].v = intstk->intstk$q_r27; + excp_regs.gr[28].v = intstk->intstk$q_r28; + excp_regs.gr[29].v = intstk->intstk$q_r29; + excp_regs.gr[30].v = intstk->intstk$q_r30; + excp_regs.gr[31].v = intstk->intstk$q_r31; + excp_regs.br[0].v = intstk->intstk$q_b0; + excp_regs.br[1].v = intstk->intstk$q_b1; + excp_regs.br[2].v = intstk->intstk$q_b2; + excp_regs.br[3].v = intstk->intstk$q_b3; + excp_regs.br[4].v = intstk->intstk$q_b4; + excp_regs.br[5].v = intstk->intstk$q_b5; + excp_regs.br[6].v = intstk->intstk$q_b6; + excp_regs.br[7].v = intstk->intstk$q_b7; +} + +/* Write all registers to current thread. FIXME: not yet complete. */ + +static void +write_all_registers (struct chf$mech_array *mech) +{ + struct _intstk *intstk = + (struct _intstk *)mech->chf$q_mch_esf_addr; + + intstk->intstk$q_ipsr = excp_regs.psr.v; +} + +/* Do debugging. Report status to gdb and execute commands. */ + +static void +do_debug (struct chf$mech_array *mech) +{ + struct _intstk *intstk = + (struct _intstk *)mech->chf$q_mch_esf_addr; + unsigned int old_ast; + unsigned int old_sch; + unsigned int status; + + /* Disable ast. */ + status = sys$setast (0); + switch (status) + { + case SS$_WASCLR: + old_ast = 0; + break; + case SS$_WASSET: + old_ast = 1; + break; + default: + /* Should never happen! */ + lib$signal (status); + } + + /* Disable thread scheduling. */ + if (has_threads) + old_sch = set_thread_scheduling (0); + + read_all_registers (mech); + + /* Send stop reply packet. */ + packet_status (); + send_pkt (); + + while (one_command () == 0) + ; + + write_all_registers (mech); + + /* Re-enable scheduling. */ + if (has_threads) + set_thread_scheduling (old_sch); + + /* Re-enable AST. */ + status = sys$setast (old_ast); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); +} + +/* The condition handler. That's the core of the stub. */ + +static int +excp_handler (struct chf$signal_array *sig, + struct chf$mech_array *mech) +{ + struct chf64$signal_array *sig64 = + (struct chf64$signal_array *)mech->chf$ph_mch_sig64_addr; + unsigned int code = sig->chf$l_sig_name & STS$M_COND_ID; + unsigned int cnt = sig64->chf64$w_sig_arg_count; + unsigned __int64 pc; + unsigned int ret; + /* Self protection. FIXME: Should be per thread ? */ + static int in_handler = 0; + + /* Completly ignore some conditions (signaled indirectly by this stub). */ + switch (code) + { + case LIB$_KEYNOTFOU & STS$M_COND_ID: + return SS$_RESIGNAL_64; + default: + break; + } + + /* Protect against recursion. */ + in_handler++; + if (in_handler > 1) + { + if (in_handler == 2) + TERM_FAO ("gdbstub: exception in handler (pc=!XH)!!!/", + (&sig64->chf64$q_sig_name)[cnt - 2]); + sys$exit (sig->chf$l_sig_name); + } + + pc = (&sig64->chf64$q_sig_name)[cnt - 2]; + if (trace_excp) + TERM_FAO ("excp_handler: code: !XL, pc=!XH!/", code, pc); + + /* If break on the entry point, restore the bundle. */ + if (code == (SS$_BREAK & STS$M_COND_ID) + && pc == entry_pc + && entry_pc != 0) + { + static unsigned int entry_prot; + + if (trace_entry) + term_puts ("initial entry breakpoint\n"); + page_set_rw (entry_pc, 16, &entry_prot); + + ots$move ((void *)entry_pc, 16, entry_saved); + __fc (entry_pc); + page_restore_rw (entry_pc, 16, entry_prot); + } + + switch (code) + { + case SS$_ACCVIO & STS$M_COND_ID: + if (trace_excp <= 1) + display_excp (sig64, mech); + /* Fall through. */ + case SS$_BREAK & STS$M_COND_ID: + case SS$_OPCDEC & STS$M_COND_ID: + case SS$_TBIT & STS$M_COND_ID: + case SS$_DEBUG & STS$M_COND_ID: + if (trace_excp > 1) + { + int i; + struct _intstk *intstk = + (struct _intstk *)mech->chf$q_mch_esf_addr; + + display_excp (sig64, mech); + + TERM_FAO (" intstk: !XH!/", intstk); + for (i = 0; i < cnt + 1; i++) + TERM_FAO (" !XH!/", ((unsigned __int64 *)sig64)[i]); + } + do_debug (mech); + ret = SS$_CONTINUE_64; + break; + + default: + display_excp (sig64, mech); + ret = SS$_RESIGNAL_64; + break; + } + + in_handler--; + /* Discard selected thread registers. */ + sel_regs_pthread = 0; + return ret; +} + +/* Setup internal trace flags according to GDBSTUB$TRACE logical. */ + +static void +trace_init (void) +{ + unsigned int status, i, start; + unsigned short len; + char resstring[LNM$C_NAMLENGTH]; + static const $DESCRIPTOR (tabdesc, "LNM$DCL_LOGICAL"); + static const $DESCRIPTOR (logdesc, "GDBSTUB$TRACE"); + $DESCRIPTOR (sub_desc, resstring); + ILE3 item_lst[2]; + + item_lst[0].ile3$w_length = LNM$C_NAMLENGTH; + item_lst[0].ile3$w_code = LNM$_STRING; + item_lst[0].ile3$ps_bufaddr = resstring; + item_lst[0].ile3$ps_retlen_addr = &len; + item_lst[1].ile3$w_length = 0; + item_lst[1].ile3$w_code = 0; + + /* Translate the logical name. */ + status = SYS$TRNLNM (0, /* Attributes of the logical name. */ + (void *)&tabdesc, /* Logical name table. */ + (void *)&logdesc, /* Logical name. */ + 0, /* Access mode. */ + &item_lst); /* Item list. */ + if (status == SS$_NOLOGNAM) + return; + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + + start = 0; + for (i = 0; i <= len; i++) + { + if ((i == len || resstring[i] == ',' || resstring[i] == ';') + && i != start) + { + int j; + + sub_desc.dsc$a_pointer = resstring + start; + sub_desc.dsc$w_length = i - start; + + for (j = 0; j < NBR_DEBUG_FLAGS; j++) + if (str$case_blind_compare (&sub_desc, + (void *)&debug_flags[j].name) == 0) + { + debug_flags[j].val++; + break; + } + if (j == NBR_DEBUG_FLAGS) + TERM_FAO ("GDBSTUB$TRACE: unknown directive !AS!/", &sub_desc); + + start = i + 1; + } + } + + TERM_FAO ("GDBSTUB$TRACE=!AD ->", len, resstring); + for (i = 0; i < NBR_DEBUG_FLAGS; i++) + if (debug_flags[i].val > 0) + TERM_FAO (" !AS=!ZL", &debug_flags[i].name, debug_flags[i].val); + term_putnl (); +} + + +/* Entry point. */ + +static int +stub_start (unsigned __int64 *progxfer, void *cli_util, + EIHD *imghdr, IFD *imgfile, + unsigned int linkflag, unsigned int cliflag) +{ + static int initialized; + int i; + int cnt; + int is_attached; + IMCB *imcb; + if (initialized) + term_puts ("gdbstub: re-entry\n"); + else + initialized = 1; + + /* When attached (through SS$_DEBUG condition), the number of arguments + is 4 and PROGXFER is the PC at interruption. */ + va_count (cnt); + is_attached = cnt == 4; + + term_init (); + + /* Hello banner. */ + term_puts ("Hello from gdb stub\n"); + + trace_init (); + + if (trace_entry && !is_attached) + { + TERM_FAO ("xfer: !XH, imghdr: !XH, ifd: !XH!/", + progxfer, imghdr, imgfile); + for (i = -2; i < 8; i++) + TERM_FAO (" at !2SW: !XH!/", i, progxfer[i]); + } + + /* Search for entry point. */ + if (!is_attached) + { + entry_pc = 0; + for (i = 0; progxfer[i]; i++) + entry_pc = progxfer[i]; + + if (trace_entry) + { + if (entry_pc == 0) + { + term_puts ("No entry point\n"); + return 0; + } + else + TERM_FAO ("Entry: !XH!/",entry_pc); + } + } + else + entry_pc = progxfer[0]; + + has_threads = 0; + for (imcb = ctl$gl_imglstptr->imcb$l_flink; + imcb != ctl$gl_imglstptr; + imcb = imcb->imcb$l_flink) + { + if (ots$strcmp_eql (pthread_rtl_desc.dsc$a_pointer, + pthread_rtl_desc.dsc$w_length, + imcb->imcb$t_log_image_name + 1, + imcb->imcb$t_log_image_name[0])) + has_threads = 1; + + if (trace_images) + { + unsigned int j; + LDRIMG *ldrimg = imcb->imcb$l_ldrimg; + LDRISD *ldrisd; + + TERM_FAO ("!XA-!XA ", + imcb->imcb$l_starting_address, + imcb->imcb$l_end_address); + + switch (imcb->imcb$b_act_code) + { + case IMCB$K_MAIN_PROGRAM: + term_puts ("prog"); + break; + case IMCB$K_MERGED_IMAGE: + term_puts ("mrge"); + break; + case IMCB$K_GLOBAL_IMAGE_SECTION: + term_puts ("glob"); + break; + default: + term_puts ("????"); + } + TERM_FAO (" !AD !40AC!/", + 1, "KESU" + (imcb->imcb$b_access_mode & 3), + imcb->imcb$t_log_image_name); + + if ((long) ldrimg < 0 || trace_images < 2) + continue; + ldrisd = ldrimg->ldrimg$l_segments; + for (j = 0; j < ldrimg->ldrimg$l_segcount; j++) + { + unsigned int flags = ldrisd[j].ldrisd$i_flags; + term_puts (" "); + term_putc (flags & 0x04 ? 'R' : '-'); + term_putc (flags & 0x02 ? 'W' : '-'); + term_putc (flags & 0x01 ? 'X' : '-'); + term_puts (flags & 0x01000000 ? " Prot" : " "); + term_puts (flags & 0x04000000 ? " Shrt" : " "); + term_puts (flags & 0x08000000 ? " Shrd" : " "); + TERM_FAO (" !XA-!XA!/", + ldrisd[j].ldrisd$p_base, + (unsigned __int64) ldrisd[j].ldrisd$p_base + + ldrisd[j].ldrisd$i_len - 1); + } + ldrisd = ldrimg->ldrimg$l_dyn_seg; + if (ldrisd) + TERM_FAO (" dynamic !XA-!XA!/", + ldrisd->ldrisd$p_base, + (unsigned __int64) ldrisd->ldrisd$p_base + + ldrisd->ldrisd$i_len - 1); + } + } + + if (has_threads) + threads_init (); + + /* Wait for connection. */ + sock_init (); + + /* Set primary exception vector. */ + { + unsigned int status; + status = sys$setexv (0, excp_handler, PSL$C_USER, (__void_ptr32) &prevhnd); + if (!(status & STS$M_SUCCESS)) + LIB$SIGNAL (status); + } + + if (is_attached) + { + return excp_handler ((struct chf$signal_array *) progxfer[2], + (struct chf$mech_array *) progxfer[3]); + } + + /* Change first instruction to set a breakpoint. */ + { + /* + 01 08 00 40 00 00 [MII] break.m 0x80001 + 00 00 00 02 00 00 nop.i 0x0 + 00 00 04 00 nop.i 0x0;; + */ + static const unsigned char initbp[16] = + { 0x01, 0x08, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00 }; + unsigned int entry_prot; + unsigned int status; + + status = page_set_rw (entry_pc, 16, &entry_prot); + + if (!(status & STS$M_SUCCESS)) + { + if ((status & STS$M_COND_ID) == (SS$_NOT_PROCESS_VA & STS$M_COND_ID)) + { + /* Cannot write here. This can happen when pthreads are + used. */ + entry_pc = 0; + term_puts ("gdbstub: cannot set breakpoint on entry\n"); + } + else + LIB$SIGNAL (status); + } + + if (entry_pc != 0) + { + ots$move (entry_saved, 16, (void *)entry_pc); + ots$move ((void *)entry_pc, 16, (void *)initbp); + __fc (entry_pc); + page_restore_rw (entry_pc, 16, entry_prot); + } + } + + /* If it wasn't possible to set a breakpoint on the entry point, + accept gdb commands now. Note that registers are not updated. */ + if (entry_pc == 0) + { + while (one_command () == 0) + ; + } + + /* We will see! */ + return SS$_CONTINUE; +} + +/* Declare the entry point of this relocatable module. */ + +struct xfer_vector +{ + __int64 impure_start; + __int64 impure_end; + int (*entry) (); +}; + +#pragma __extern_model save +#pragma __extern_model strict_refdef "XFER_PSECT" +struct xfer_vector xfer_vector = {0, 0, stub_start}; +#pragma __extern_model restore diff --git a/contrib/gdb-7/gdb/stubs/m32r-stub.c b/contrib/gdb-7/gdb/stubs/m32r-stub.c new file mode 100644 index 0000000000..4d54f72d60 --- /dev/null +++ b/contrib/gdb-7/gdb/stubs/m32r-stub.c @@ -0,0 +1,1779 @@ +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for M32R by Michael Snyder, Cygnus Support. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + * The external function exceptionHandler() is + * used to attach a specific handler to a specific M32R vector number. + * It should use the same privilege level it runs at. It should + * install it as an interrupt gate so that interrupts are masked + * while the handler runs. + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * XAA..AA,LLLL: Write LLLL binary bytes at address OK or ENN + * AA..AA + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + + +/************************************************************************ + * + * external low-level support routines + */ +extern void putDebugChar (); /* write a single character */ +extern int getDebugChar (); /* read and return a single char */ +extern void exceptionHandler (); /* assign an exception handler */ + +/***************************************************************************** + * BUFMAX defines the maximum number of characters in inbound/outbound buffers + * at least NUMREGBYTES*2 are needed for register packets + */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const unsigned char hexchars[] = "0123456789abcdef"; + +#define NUMREGS 24 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) +enum regnames +{ R0, R1, R2, R3, R4, R5, R6, R7, + R8, R9, R10, R11, R12, R13, R14, R15, + PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH +}; + +enum SYS_calls +{ + SYS_null, + SYS_exit, + SYS_open, + SYS_close, + SYS_read, + SYS_write, + SYS_lseek, + SYS_unlink, + SYS_getpid, + SYS_kill, + SYS_fstat, + SYS_sbrk, + SYS_fork, + SYS_execve, + SYS_wait4, + SYS_link, + SYS_chdir, + SYS_stat, + SYS_utime, + SYS_chown, + SYS_chmod, + SYS_time, + SYS_pipe +}; + +static int registers[NUMREGS]; + +#define STACKSIZE 8096 +static unsigned char remcomInBuffer[BUFMAX]; +static unsigned char remcomOutBuffer[BUFMAX]; +static int remcomStack[STACKSIZE / sizeof (int)]; +static int *stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + +static unsigned int save_vectors[18]; /* previous exception vectors */ + +/* Indicate to caller of mem2hex or hex2mem that there has been an error. */ +static volatile int mem_err = 0; + +/* Store the vector number here (since GDB only gets the signal + number through the usual means, and that's not very specific). */ +int gdb_m32r_vector = -1; + +#if 0 +#include "syscall.h" /* for SYS_exit, SYS_write etc. */ +#endif + +/* Global entry points: + */ + +extern void handle_exception (int); +extern void set_debug_traps (void); +extern void breakpoint (void); + +/* Local functions: + */ + +static int computeSignal (int); +static void putpacket (unsigned char *); +static unsigned char *getpacket (void); + +static unsigned char *mem2hex (unsigned char *, unsigned char *, int, int); +static unsigned char *hex2mem (unsigned char *, unsigned char *, int, int); +static int hexToInt (unsigned char **, int *); +static unsigned char *bin2mem (unsigned char *, unsigned char *, int, int); +static void stash_registers (void); +static void restore_registers (void); +static int prepare_to_step (int); +static int finish_from_step (void); +static unsigned long crc32 (unsigned char *, int, unsigned long); + +static void gdb_error (char *, char *); +static int gdb_putchar (int), gdb_puts (char *), gdb_write (char *, int); + +static unsigned char *strcpy (unsigned char *, const unsigned char *); +static int strlen (const unsigned char *); + +/* + * This function does all command procesing for interfacing to gdb. + */ + +void +handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length, i; + unsigned char *ptr; + unsigned char buf[16]; + int binary; + + if (!finish_from_step ()) + return; /* "false step": let the target continue */ + + gdb_m32r_vector = exceptionVector; + + if (remote_debug) + { + mem2hex ((unsigned char *) &exceptionVector, buf, 4, 0); + gdb_error ("Handle exception %s, ", buf); + mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0); + gdb_error ("PC == 0x%s\n", buf); + } + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + + ptr = remcomOutBuffer; + + *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[PC >> 4]; + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); /* PC */ + *ptr++ = ';'; + + *ptr++ = hexchars[R13 >> 4]; + *ptr++ = hexchars[R13 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); /* FP */ + *ptr++ = ';'; + + *ptr++ = hexchars[R15 >> 4]; + *ptr++ = hexchars[R15 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); /* SP */ + *ptr++ = ';'; + *ptr++ = 0; + + if (exceptionVector == 0) /* simulated SYS call stuff */ + { + mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0); + switch (registers[R0]) + { + case SYS_exit: + gdb_error ("Target program has exited at %s\n", buf); + ptr = remcomOutBuffer; + *ptr++ = 'W'; + sigval = registers[R1] & 0xff; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + *ptr++ = 0; + break; + case SYS_open: + gdb_error ("Target attempts SYS_open call at %s\n", buf); + break; + case SYS_close: + gdb_error ("Target attempts SYS_close call at %s\n", buf); + break; + case SYS_read: + gdb_error ("Target attempts SYS_read call at %s\n", buf); + break; + case SYS_write: + if (registers[R1] == 1 || /* write to stdout */ + registers[R1] == 2) /* write to stderr */ + { /* (we can do that) */ + registers[R0] = + gdb_write ((void *) registers[R2], registers[R3]); + return; + } + else + gdb_error ("Target attempts SYS_write call at %s\n", buf); + break; + case SYS_lseek: + gdb_error ("Target attempts SYS_lseek call at %s\n", buf); + break; + case SYS_unlink: + gdb_error ("Target attempts SYS_unlink call at %s\n", buf); + break; + case SYS_getpid: + gdb_error ("Target attempts SYS_getpid call at %s\n", buf); + break; + case SYS_kill: + gdb_error ("Target attempts SYS_kill call at %s\n", buf); + break; + case SYS_fstat: + gdb_error ("Target attempts SYS_fstat call at %s\n", buf); + break; + default: + gdb_error ("Target attempts unknown SYS call at %s\n", buf); + break; + } + } + + putpacket (remcomOutBuffer); + + stepping = 0; + + while (1 == 1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + binary = 0; + switch (*ptr++) + { + default: /* Unknown code. Return an empty reply message. */ + break; + case 'R': + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + strcpy (remcomOutBuffer, "OK"); + break; + case '!': + strcpy (remcomOutBuffer, "OK"); + break; + case 'X': /* XAA..AA,LLLL:#cs */ + binary = 1; + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + { + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + mem_err = 0; + if (binary) + bin2mem (ptr, (unsigned char *) addr, length, 1); + else + hex2mem (ptr, (unsigned char *) addr, length, 1); + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + gdb_error ("memory fault", ""); + } + else + { + strcpy (remcomOutBuffer, "OK"); + } + ptr = 0; + } + if (ptr) + { + strcpy (remcomOutBuffer, "E02"); + } + } + break; + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem_err = 0; + mem2hex ((unsigned char *) addr, remcomOutBuffer, length, + 1); + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + gdb_error ("memory fault", ""); + } + } + if (ptr) + { + strcpy (remcomOutBuffer, "E01"); + } + break; + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((unsigned char *) registers, remcomOutBuffer, NUMREGBYTES, + 0); + break; + case 'P': /* set the value of a single CPU register - return OK */ + { + int regno; + + if (hexToInt (&ptr, ®no) && *ptr++ == '=') + if (regno >= 0 && regno < NUMREGS) + { + int stackmode; + + hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0); + /* + * Since we just changed a single CPU register, let's + * make sure to keep the several stack pointers consistant. + */ + stackmode = registers[PSW] & 0x80; + if (regno == R15) /* stack pointer changed */ + { /* need to change SPI or SPU */ + if (stackmode == 0) + registers[SPI] = registers[R15]; + else + registers[SPU] = registers[R15]; + } + else if (regno == SPU) /* "user" stack pointer changed */ + { + if (stackmode != 0) /* stack in user mode: copy SP */ + registers[R15] = registers[SPU]; + } + else if (regno == SPI) /* "interrupt" stack pointer changed */ + { + if (stackmode == 0) /* stack in interrupt mode: copy SP */ + registers[R15] = registers[SPI]; + } + else if (regno == PSW) /* stack mode may have changed! */ + { /* force SP to either SPU or SPI */ + if (stackmode == 0) /* stack in user mode */ + registers[R15] = registers[SPI]; + else /* stack in interrupt mode */ + registers[R15] = registers[SPU]; + } + strcpy (remcomOutBuffer, "OK"); + break; + } + strcpy (remcomOutBuffer, "E01"); + break; + } + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (unsigned char *) registers, NUMREGBYTES, 0); + strcpy (remcomOutBuffer, "OK"); + break; + case 's': /* sAA..AA Step one instruction from AA..AA(optional) */ + stepping = 1; + case 'c': /* cAA..AA Continue from address AA..AA(optional) */ + /* try to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + if (stepping) /* single-stepping */ + { + if (!prepare_to_step (0)) /* set up for single-step */ + { + /* prepare_to_step has already emulated the target insn: + Send SIGTRAP to gdb, don't resume the target at all. */ + ptr = remcomOutBuffer; + *ptr++ = 'T'; /* Simulate stopping with SIGTRAP */ + *ptr++ = '0'; + *ptr++ = '5'; + + *ptr++ = hexchars[PC >> 4]; /* send PC */ + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R13 >> 4]; /* send FP */ + *ptr++ = hexchars[R13 & 0xf]; + *ptr++ = ':'; + ptr = + mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R15 >> 4]; /* send SP */ + *ptr++ = hexchars[R15 & 0xf]; + *ptr++ = ':'; + ptr = + mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); + *ptr++ = ';'; + *ptr++ = 0; + + break; + } + } + else /* continuing, not single-stepping */ + { + /* OK, about to do a "continue". First check to see if the + target pc is on an odd boundary (second instruction in the + word). If so, we must do a single-step first, because + ya can't jump or return back to an odd boundary! */ + if ((registers[PC] & 2) != 0) + prepare_to_step (1); + } + + return; + + case 'D': /* Detach */ +#if 0 + /* I am interpreting this to mean, release the board from control + by the remote stub. To do this, I am restoring the original + (or at least previous) exception vectors. + */ + for (i = 0; i < 18; i++) + exceptionHandler (i, save_vectors[i]); + putpacket ("OK"); + return; /* continue the inferior */ +#else + strcpy (remcomOutBuffer, "OK"); + break; +#endif + case 'q': + if (*ptr++ == 'C' && + *ptr++ == 'R' && *ptr++ == 'C' && *ptr++ == ':') + { + unsigned long start, len, our_crc; + + if (hexToInt (&ptr, (int *) &start) && + *ptr++ == ',' && hexToInt (&ptr, (int *) &len)) + { + remcomOutBuffer[0] = 'C'; + our_crc = crc32 ((unsigned char *) start, len, 0xffffffff); + mem2hex ((char *) &our_crc, + &remcomOutBuffer[1], sizeof (long), 0); + } /* else do nothing */ + } /* else do nothing */ + break; + + case 'k': /* kill the program */ + continue; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + +/* qCRC support */ + +/* Table used by the crc32 function to calcuate the checksum. */ +static unsigned long crc32_table[256] = { 0, 0 }; + +static unsigned long +crc32 (unsigned char *buf, int len, unsigned long crc) +{ + if (!crc32_table[1]) + { + /* Initialize the CRC table and the decoding table. */ + int i, j; + unsigned long c; + + for (i = 0; i < 256; i++) + { + for (c = i << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); + crc32_table[i] = c; + } + } + + while (len--) + { + crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; + buf++; + } + return crc; +} + +static int +hex (unsigned char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ + +unsigned char * +getpacket (void) +{ + unsigned char *buffer = &remcomInBuffer[0]; + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + while (1) + { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar ()) != '$') + ; + + retry: + checksum = 0; + xmitcsum = -1; + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX - 1) + { + ch = getDebugChar (); + if (ch == '$') + goto retry; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + ch = getDebugChar (); + xmitcsum = hex (ch) << 4; + ch = getDebugChar (); + xmitcsum += hex (ch); + + if (checksum != xmitcsum) + { + if (remote_debug) + { + unsigned char buf[16]; + + mem2hex ((unsigned char *) &checksum, buf, 4, 0); + gdb_error ("Bad checksum: my count = %s, ", buf); + mem2hex ((unsigned char *) &xmitcsum, buf, 4, 0); + gdb_error ("sent count = %s\n", buf); + gdb_error (" -- Bad buffer: \"%s\"\n", buffer); + } + putDebugChar ('-'); /* failed checksum */ + } + else + { + putDebugChar ('+'); /* successful transfer */ + + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + return &buffer[3]; + } + + return &buffer[0]; + } + } + } +} + +/* send the packet in buffer. */ + +static void +putpacket (unsigned char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum % 16]); + } + while (getDebugChar () != '+'); +} + +/* Address of a routine to RTE to if we get a memory fault. */ + +static void (*volatile mem_fault_routine) () = 0; + +static void +set_mem_err (void) +{ + mem_err = 1; +} + +/* Check the address for safe access ranges. As currently defined, + this routine will reject the "expansion bus" address range(s). + To make those ranges useable, someone must implement code to detect + whether there's anything connected to the expansion bus. */ + +static int +mem_safe (unsigned char *addr) +{ +#define BAD_RANGE_ONE_START ((unsigned char *) 0x600000) +#define BAD_RANGE_ONE_END ((unsigned char *) 0xa00000) +#define BAD_RANGE_TWO_START ((unsigned char *) 0xff680000) +#define BAD_RANGE_TWO_END ((unsigned char *) 0xff800000) + + if (addr < BAD_RANGE_ONE_START) + return 1; /* safe */ + if (addr < BAD_RANGE_ONE_END) + return 0; /* unsafe */ + if (addr < BAD_RANGE_TWO_START) + return 1; /* safe */ + if (addr < BAD_RANGE_TWO_END) + return 0; /* unsafe */ +} + +/* These are separate functions so that they are so short and sweet + that the compiler won't save any registers (if there is a fault + to mem_fault, they won't get restored, so there better not be any + saved). */ +static int +get_char (unsigned char *addr) +{ +#if 1 + if (mem_fault_routine && !mem_safe (addr)) + { + mem_fault_routine (); + return 0; + } +#endif + return *addr; +} + +static void +set_char (unsigned char *addr, unsigned char val) +{ +#if 1 + if (mem_fault_routine && !mem_safe (addr)) + { + mem_fault_routine (); + return; + } +#endif + *addr = val; +} + +/* Convert the memory pointed to by mem into hex, placing result in buf. + Return a pointer to the last char put in buf (null). + If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ + +static unsigned char * +mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = get_char (mem++); + if (may_fault && mem_err) + return (buf); + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_fault_routine = 0; + return (buf); +} + +/* Convert the hex array pointed to by buf into binary to be placed in mem. + Return a pointer to the character AFTER the last byte written. */ + +static unsigned char * +hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + set_char (mem++, ch); + if (may_fault && mem_err) + return (mem); + } + if (may_fault) + mem_fault_routine = 0; + return (mem); +} + +/* Convert the binary stream in BUF to memory. + + Gdb will escape $, #, and the escape char (0x7d). + COUNT is the total number of bytes to write into + memory. */ +static unsigned char * +bin2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + /* Check for any escaped characters. Be paranoid and + only unescape chars that should be escaped. */ + if (*buf == 0x7d) + { + switch (*(buf + 1)) + { + case 0x3: /* # */ + case 0x4: /* $ */ + case 0x5d: /* escape char */ + buf++; + *buf |= 0x20; + break; + default: + /* nothing */ + break; + } + } + + set_char (mem++, *buf++); + + if (may_fault && mem_err) + return mem; + } + + if (may_fault) + mem_fault_routine = 0; + return mem; +} + +/* this function takes the m32r exception vector and attempts to + translate this number into a unix compatible signal value */ + +static int +computeSignal (int exceptionVector) +{ + int sigval; + switch (exceptionVector) + { + case 0: + sigval = 23; + break; /* I/O trap */ + case 1: + sigval = 5; + break; /* breakpoint */ + case 2: + sigval = 5; + break; /* breakpoint */ + case 3: + sigval = 5; + break; /* breakpoint */ + case 4: + sigval = 5; + break; /* breakpoint */ + case 5: + sigval = 5; + break; /* breakpoint */ + case 6: + sigval = 5; + break; /* breakpoint */ + case 7: + sigval = 5; + break; /* breakpoint */ + case 8: + sigval = 5; + break; /* breakpoint */ + case 9: + sigval = 5; + break; /* breakpoint */ + case 10: + sigval = 5; + break; /* breakpoint */ + case 11: + sigval = 5; + break; /* breakpoint */ + case 12: + sigval = 5; + break; /* breakpoint */ + case 13: + sigval = 5; + break; /* breakpoint */ + case 14: + sigval = 5; + break; /* breakpoint */ + case 15: + sigval = 5; + break; /* breakpoint */ + case 16: + sigval = 10; + break; /* BUS ERROR (alignment) */ + case 17: + sigval = 2; + break; /* INTerrupt */ + default: + sigval = 7; + break; /* "software generated" */ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +static int +hexToInt (unsigned char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + while (**ptr) + { + hexValue = hex (**ptr); + if (hexValue >= 0) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + (*ptr)++; + } + return (numChars); +} + +/* + Table of branch instructions: + + 10B6 RTE return from trap or exception + 1FCr JMP jump + 1ECr JL jump and link + 7Fxx BRA branch + FFxxxxxx BRA branch (long) + B09rxxxx BNEZ branch not-equal-zero + Br1rxxxx BNE branch not-equal + 7Dxx BNC branch not-condition + FDxxxxxx BNC branch not-condition (long) + B0Arxxxx BLTZ branch less-than-zero + B0Crxxxx BLEZ branch less-equal-zero + 7Exx BL branch and link + FExxxxxx BL branch and link (long) + B0Drxxxx BGTZ branch greater-than-zero + B0Brxxxx BGEZ branch greater-equal-zero + B08rxxxx BEQZ branch equal-zero + Br0rxxxx BEQ branch equal + 7Cxx BC branch condition + FCxxxxxx BC branch condition (long) + */ + +static int +isShortBranch (unsigned char *instr) +{ + unsigned char instr0 = instr[0] & 0x7F; /* mask off high bit */ + + if (instr0 == 0x10 && instr[1] == 0xB6) /* RTE */ + return 1; /* return from trap or exception */ + + if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */ + if ((instr[1] & 0xF0) == 0xC0) + return 2; /* jump thru a register */ + + if (instr0 == 0x7C || instr0 == 0x7D || /* BC, BNC, BL, BRA */ + instr0 == 0x7E || instr0 == 0x7F) + return 3; /* eight bit PC offset */ + + return 0; +} + +static int +isLongBranch (unsigned char *instr) +{ + if (instr[0] == 0xFC || instr[0] == 0xFD || /* BRA, BNC, BL, BC */ + instr[0] == 0xFE || instr[0] == 0xFF) /* 24 bit relative */ + return 4; + if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */ + { + if ((instr[1] & 0xF0) == 0x00 || /* BNE, BEQ */ + (instr[1] & 0xF0) == 0x10) + return 5; + if (instr[0] == 0xB0) /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */ + if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 || + (instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 || + (instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0) + return 6; + } + return 0; +} + +/* if address is NOT on a 4-byte boundary, or high-bit of instr is zero, + then it's a 2-byte instruction, else it's a 4-byte instruction. */ + +#define INSTRUCTION_SIZE(addr) \ + ((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4) + +static int +isBranch (unsigned char *instr) +{ + if (INSTRUCTION_SIZE (instr) == 2) + return isShortBranch (instr); + else + return isLongBranch (instr); +} + +static int +willBranch (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + case 0: + return 0; /* not a branch */ + case 1: + return 1; /* RTE */ + case 2: + return 1; /* JL or JMP */ + case 3: /* BC, BNC, BL, BRA (short) */ + case 4: /* BC, BNC, BL, BRA (long) */ + switch (instr[0] & 0x0F) + { + case 0xC: /* Branch if Condition Register */ + return (registers[CBR] != 0); + case 0xD: /* Branch if NOT Condition Register */ + return (registers[CBR] == 0); + case 0xE: /* Branch and Link */ + case 0xF: /* Branch (unconditional) */ + return 1; + default: /* oops? */ + return 0; + } + case 5: /* BNE, BEQ */ + switch (instr[1] & 0xF0) + { + case 0x00: /* Branch if r1 equal to r2 */ + return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]); + case 0x10: /* Branch if r1 NOT equal to r2 */ + return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]); + default: /* oops? */ + return 0; + } + case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */ + switch (instr[1] & 0xF0) + { + case 0x80: /* Branch if reg equal to zero */ + return (registers[instr[1] & 0x0F] == 0); + case 0x90: /* Branch if reg NOT equal to zero */ + return (registers[instr[1] & 0x0F] != 0); + case 0xA0: /* Branch if reg less than zero */ + return (registers[instr[1] & 0x0F] < 0); + case 0xB0: /* Branch if reg greater or equal to zero */ + return (registers[instr[1] & 0x0F] >= 0); + case 0xC0: /* Branch if reg less than or equal to zero */ + return (registers[instr[1] & 0x0F] <= 0); + case 0xD0: /* Branch if reg greater than zero */ + return (registers[instr[1] & 0x0F] > 0); + default: /* oops? */ + return 0; + } + default: /* oops? */ + return 0; + } +} + +static int +branchDestination (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + default: + case 0: /* not a branch */ + return 0; + case 1: /* RTE */ + return registers[BPC] & ~3; /* pop BPC into PC */ + case 2: /* JL or JMP */ + return registers[instr[1] & 0x0F] & ~3; /* jump thru a register */ + case 3: /* BC, BNC, BL, BRA (short, 8-bit relative offset) */ + return (((int) instr) & ~3) + ((char) instr[1] << 2); + case 4: /* BC, BNC, BL, BRA (long, 24-bit relative offset) */ + return ((int) instr + + ((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) << + 2)); + case 5: /* BNE, BEQ (16-bit relative offset) */ + case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */ + return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2)); + } + + /* An explanatory note: in the last three return expressions, I have + cast the most-significant byte of the return offset to char. + What this accomplishes is sign extension. If the other + less-significant bytes were signed as well, they would get sign + extended too and, if negative, their leading bits would clobber + the bits of the more-significant bytes ahead of them. There are + other ways I could have done this, but sign extension from + odd-sized integers is always a pain. */ +} + +static void +branchSideEffects (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + case 1: /* RTE */ + return; /* I this is already handled... */ + case 2: /* JL (or JMP) */ + case 3: /* BL (or BC, BNC, BRA) */ + case 4: + if ((instr[0] & 0x0F) == 0x0E) /* branch/jump and link */ + registers[R14] = (registers[PC] & ~3) + 4; + return; + default: /* any other branch has no side effects */ + return; + } +} + +static struct STEPPING_CONTEXT +{ + int stepping; /* true when we've started a single-step */ + unsigned long target_addr; /* the instr we're trying to execute */ + unsigned long target_size; /* the size of the target instr */ + unsigned long noop_addr; /* where we've inserted a no-op, if any */ + unsigned long trap1_addr; /* the trap following the target instr */ + unsigned long trap2_addr; /* the trap at a branch destination, if any */ + unsigned short noop_save; /* instruction overwritten by our no-op */ + unsigned short trap1_save; /* instruction overwritten by trap1 */ + unsigned short trap2_save; /* instruction overwritten by trap2 */ + unsigned short continue_p; /* true if NOT returning to gdb after step */ +} stepping; + +/* Function: prepare_to_step + Called from handle_exception to prepare the user program to single-step. + Places a trap instruction after the target instruction, with special + extra handling for branch instructions and for instructions in the + second half-word of a word. + + Returns: True if we should actually execute the instruction; + False if we are going to emulate executing the instruction, + in which case we simply report to GDB that the instruction + has already been executed. */ + +#define TRAP1 0x10f1; /* trap #1 instruction */ +#define NOOP 0x7000; /* noop instruction */ + +static unsigned short trap1 = TRAP1; +static unsigned short noop = NOOP; + +static int +prepare_to_step (continue_p) + int continue_p; /* if this isn't REALLY a single-step (see below) */ +{ + unsigned long pc = registers[PC]; + int branchCode = isBranch ((unsigned char *) pc); + unsigned char *p; + + /* zero out the stepping context + (paranoia -- it should already be zeroed) */ + for (p = (unsigned char *) &stepping; + p < ((unsigned char *) &stepping) + sizeof (stepping); p++) + *p = 0; + + if (branchCode != 0) /* next instruction is a branch */ + { + branchSideEffects ((unsigned char *) pc, branchCode); + if (willBranch ((unsigned char *) pc, branchCode)) + registers[PC] = branchDestination ((unsigned char *) pc, branchCode); + else + registers[PC] = pc + INSTRUCTION_SIZE (pc); + return 0; /* branch "executed" -- just notify GDB */ + } + else if (((int) pc & 2) != 0) /* "second-slot" instruction */ + { + /* insert no-op before pc */ + stepping.noop_addr = pc - 2; + stepping.noop_save = *(unsigned short *) stepping.noop_addr; + *(unsigned short *) stepping.noop_addr = noop; + /* insert trap after pc */ + stepping.trap1_addr = pc + 2; + stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; + *(unsigned short *) stepping.trap1_addr = trap1; + } + else /* "first-slot" instruction */ + { + /* insert trap after pc */ + stepping.trap1_addr = pc + INSTRUCTION_SIZE (pc); + stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; + *(unsigned short *) stepping.trap1_addr = trap1; + } + /* "continue_p" means that we are actually doing a continue, and not + being requested to single-step by GDB. Sometimes we have to do + one single-step before continuing, because the PC is on a half-word + boundary. There's no way to simply resume at such an address. */ + stepping.continue_p = continue_p; + stepping.stepping = 1; /* starting a single-step */ + return 1; +} + +/* Function: finish_from_step + Called from handle_exception to finish up when the user program + returns from a single-step. Replaces the instructions that had + been overwritten by traps or no-ops, + + Returns: True if we should notify GDB that the target stopped. + False if we only single-stepped because we had to before we + could continue (ie. we were trying to continue at a + half-word boundary). In that case don't notify GDB: + just "continue continuing". */ + +static int +finish_from_step (void) +{ + if (stepping.stepping) /* anything to do? */ + { + int continue_p = stepping.continue_p; + unsigned char *p; + + if (stepping.noop_addr) /* replace instr "under" our no-op */ + *(unsigned short *) stepping.noop_addr = stepping.noop_save; + if (stepping.trap1_addr) /* replace instr "under" our trap */ + *(unsigned short *) stepping.trap1_addr = stepping.trap1_save; + if (stepping.trap2_addr) /* ditto our other trap, if any */ + *(unsigned short *) stepping.trap2_addr = stepping.trap2_save; + + for (p = (unsigned char *) &stepping; /* zero out the stepping context */ + p < ((unsigned char *) &stepping) + sizeof (stepping); p++) + *p = 0; + + return !(continue_p); + } + else /* we didn't single-step, therefore this must be a legitimate stop */ + return 1; +} + +struct PSWreg +{ /* separate out the bit flags in the PSW register */ + int pad1:16; + int bsm:1; + int bie:1; + int pad2:5; + int bc:1; + int sm:1; + int ie:1; + int pad3:5; + int c:1; +} *psw; + +/* Upon entry the value for LR to save has been pushed. + We unpush that so that the value for the stack pointer saved is correct. + Upon entry, all other registers are assumed to have not been modified + since the interrupt/trap occured. */ + +asm ("\n\ +stash_registers:\n\ + push r0\n\ + push r1\n\ + seth r1, #shigh(registers)\n\ + add3 r1, r1, #low(registers)\n\ + pop r0 ; r1\n\ + st r0, @(4,r1)\n\ + pop r0 ; r0\n\ + st r0, @r1\n\ + addi r1, #4 ; only add 4 as subsequent saves are `pre inc'\n\ + st r2, @+r1\n\ + st r3, @+r1\n\ + st r4, @+r1\n\ + st r5, @+r1\n\ + st r6, @+r1\n\ + st r7, @+r1\n\ + st r8, @+r1\n\ + st r9, @+r1\n\ + st r10, @+r1\n\ + st r11, @+r1\n\ + st r12, @+r1\n\ + st r13, @+r1 ; fp\n\ + pop r0 ; lr (r14)\n\ + st r0, @+r1\n\ + st sp, @+r1 ; sp contains right value at this point\n\ + mvfc r0, cr0\n\ + st r0, @+r1 ; cr0 == PSW\n\ + mvfc r0, cr1\n\ + st r0, @+r1 ; cr1 == CBR\n\ + mvfc r0, cr2\n\ + st r0, @+r1 ; cr2 == SPI\n\ + mvfc r0, cr3\n\ + st r0, @+r1 ; cr3 == SPU\n\ + mvfc r0, cr6\n\ + st r0, @+r1 ; cr6 == BPC\n\ + st r0, @+r1 ; PC == BPC\n\ + mvfaclo r0\n\ + st r0, @+r1 ; ACCL\n\ + mvfachi r0\n\ + st r0, @+r1 ; ACCH\n\ + jmp lr"); + +/* C routine to clean up what stash_registers did. + It is called after calling stash_registers. + This is separate from stash_registers as we want to do this in C + but doing stash_registers in C isn't straightforward. */ + +static void +cleanup_stash (void) +{ + psw = (struct PSWreg *) ®isters[PSW]; /* fields of PSW register */ + psw->sm = psw->bsm; /* fix up pre-trap values of psw fields */ + psw->ie = psw->bie; + psw->c = psw->bc; + registers[CBR] = psw->bc; /* fix up pre-trap "C" register */ + +#if 0 /* FIXME: Was in previous version. Necessary? + (Remember that we use the "rte" insn to return from the + trap/interrupt so the values of bsm, bie, bc are important. */ + psw->bsm = psw->bie = psw->bc = 0; /* zero post-trap values */ +#endif + + /* FIXME: Copied from previous version. This can probably be deleted + since methinks stash_registers has already done this. */ + registers[PC] = registers[BPC]; /* pre-trap PC */ + + /* FIXME: Copied from previous version. Necessary? */ + if (psw->sm) /* copy R15 into (psw->sm ? SPU : SPI) */ + registers[SPU] = registers[R15]; + else + registers[SPI] = registers[R15]; +} + +asm ("\n\ +restore_and_return:\n\ + seth r0, #shigh(registers+8)\n\ + add3 r0, r0, #low(registers+8)\n\ + ld r2, @r0+ ; restore r2\n\ + ld r3, @r0+ ; restore r3\n\ + ld r4, @r0+ ; restore r4\n\ + ld r5, @r0+ ; restore r5\n\ + ld r6, @r0+ ; restore r6\n\ + ld r7, @r0+ ; restore r7\n\ + ld r8, @r0+ ; restore r8\n\ + ld r9, @r0+ ; restore r9\n\ + ld r10, @r0+ ; restore r10\n\ + ld r11, @r0+ ; restore r11\n\ + ld r12, @r0+ ; restore r12\n\ + ld r13, @r0+ ; restore r13\n\ + ld r14, @r0+ ; restore r14\n\ + ld r15, @r0+ ; restore r15\n\ + ld r1, @r0+ ; restore cr0 == PSW\n\ + mvtc r1, cr0\n\ + ld r1, @r0+ ; restore cr1 == CBR (no-op, because it's read only)\n\ + mvtc r1, cr1\n\ + ld r1, @r0+ ; restore cr2 == SPI\n\ + mvtc r1, cr2\n\ + ld r1, @r0+ ; restore cr3 == SPU\n\ + mvtc r1, cr3\n\ + addi r0, #4 ; skip BPC\n\ + ld r1, @r0+ ; restore cr6 (BPC) == PC\n\ + mvtc r1, cr6\n\ + ld r1, @r0+ ; restore ACCL\n\ + mvtaclo r1\n\ + ld r1, @r0+ ; restore ACCH\n\ + mvtachi r1\n\ + seth r0, #shigh(registers)\n\ + add3 r0, r0, #low(registers)\n\ + ld r1, @(4,r0) ; restore r1\n\ + ld r0, @r0 ; restore r0\n\ + rte"); + +/* General trap handler, called after the registers have been stashed. + NUM is the trap/exception number. */ + +static void +process_exception (int num) +{ + cleanup_stash (); + asm volatile ("\n\ + seth r1, #shigh(stackPtr)\n\ + add3 r1, r1, #low(stackPtr)\n\ + ld r15, @r1 ; setup local stack (protect user stack)\n\ + mv r0, %0\n\ + bl handle_exception\n\ + bl restore_and_return"::"r" (num):"r0", "r1"); +} + +void _catchException0 (); + +asm ("\n\ +_catchException0:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #0\n\ + bl process_exception"); + +void _catchException1 (); + +asm ("\n\ +_catchException1:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + bl cleanup_stash\n\ + seth r1, #shigh(stackPtr)\n\ + add3 r1, r1, #low(stackPtr)\n\ + ld r15, @r1 ; setup local stack (protect user stack)\n\ + seth r1, #shigh(registers + 21*4) ; PC\n\ + add3 r1, r1, #low(registers + 21*4)\n\ + ld r0, @r1\n\ + addi r0, #-4 ; back up PC for breakpoint trap.\n\ + st r0, @r1 ; FIXME: what about bp in right slot?\n\ + ldi r0, #1\n\ + bl handle_exception\n\ + bl restore_and_return"); + +void _catchException2 (); + +asm ("\n\ +_catchException2:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #2\n\ + bl process_exception"); + +void _catchException3 (); + +asm ("\n\ +_catchException3:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #3\n\ + bl process_exception"); + +void _catchException4 (); + +asm ("\n\ +_catchException4:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #4\n\ + bl process_exception"); + +void _catchException5 (); + +asm ("\n\ +_catchException5:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #5\n\ + bl process_exception"); + +void _catchException6 (); + +asm ("\n\ +_catchException6:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #6\n\ + bl process_exception"); + +void _catchException7 (); + +asm ("\n\ +_catchException7:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #7\n\ + bl process_exception"); + +void _catchException8 (); + +asm ("\n\ +_catchException8:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #8\n\ + bl process_exception"); + +void _catchException9 (); + +asm ("\n\ +_catchException9:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #9\n\ + bl process_exception"); + +void _catchException10 (); + +asm ("\n\ +_catchException10:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #10\n\ + bl process_exception"); + +void _catchException11 (); + +asm ("\n\ +_catchException11:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #11\n\ + bl process_exception"); + +void _catchException12 (); + +asm ("\n\ +_catchException12:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #12\n\ + bl process_exception"); + +void _catchException13 (); + +asm ("\n\ +_catchException13:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #13\n\ + bl process_exception"); + +void _catchException14 (); + +asm ("\n\ +_catchException14:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #14\n\ + bl process_exception"); + +void _catchException15 (); + +asm ("\n\ +_catchException15:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #15\n\ + bl process_exception"); + +void _catchException16 (); + +asm ("\n\ +_catchException16:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #16\n\ + bl process_exception"); + +void _catchException17 (); + +asm ("\n\ +_catchException17:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #17\n\ + bl process_exception"); + + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void +set_debug_traps (void) +{ + /* extern void remcomHandler(); */ + int i; + + for (i = 0; i < 18; i++) /* keep a copy of old vectors */ + if (save_vectors[i] == 0) /* only copy them the first time */ + save_vectors[i] = getExceptionHandler (i); + + stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + + exceptionHandler (0, _catchException0); + exceptionHandler (1, _catchException1); + exceptionHandler (2, _catchException2); + exceptionHandler (3, _catchException3); + exceptionHandler (4, _catchException4); + exceptionHandler (5, _catchException5); + exceptionHandler (6, _catchException6); + exceptionHandler (7, _catchException7); + exceptionHandler (8, _catchException8); + exceptionHandler (9, _catchException9); + exceptionHandler (10, _catchException10); + exceptionHandler (11, _catchException11); + exceptionHandler (12, _catchException12); + exceptionHandler (13, _catchException13); + exceptionHandler (14, _catchException14); + exceptionHandler (15, _catchException15); + exceptionHandler (16, _catchException16); + /* exceptionHandler (17, _catchException17); */ + + initialized = 1; +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +#define BREAKPOINT() asm volatile (" trap #2"); + +void +breakpoint (void) +{ + if (initialized) + BREAKPOINT (); +} + +/* STDOUT section: + Stuff pertaining to simulating stdout by sending chars to gdb to be echoed. + Functions: gdb_putchar(char ch) + gdb_puts(char *str) + gdb_write(char *str, int len) + gdb_error(char *format, char *parm) + */ + +/* Function: gdb_putchar(int) + Make gdb write a char to stdout. + Returns: the char */ + +static int +gdb_putchar (int ch) +{ + char buf[4]; + + buf[0] = 'O'; + buf[1] = hexchars[ch >> 4]; + buf[2] = hexchars[ch & 0x0F]; + buf[3] = 0; + putpacket (buf); + return ch; +} + +/* Function: gdb_write(char *, int) + Make gdb write n bytes to stdout (not assumed to be null-terminated). + Returns: number of bytes written */ + +static int +gdb_write (char *data, int len) +{ + char *buf, *cpy; + int i; + + buf = remcomOutBuffer; + buf[0] = 'O'; + i = 0; + while (i < len) + { + for (cpy = buf + 1; + i < len && cpy < buf + sizeof (remcomOutBuffer) - 3; i++) + { + *cpy++ = hexchars[data[i] >> 4]; + *cpy++ = hexchars[data[i] & 0x0F]; + } + *cpy = 0; + putpacket (buf); + } + return len; +} + +/* Function: gdb_puts(char *) + Make gdb write a null-terminated string to stdout. + Returns: the length of the string */ + +static int +gdb_puts (char *str) +{ + return gdb_write (str, strlen (str)); +} + +/* Function: gdb_error(char *, char *) + Send an error message to gdb's stdout. + First string may have 1 (one) optional "%s" in it, which + will cause the optional second string to be inserted. */ + +static void +gdb_error (char *format, char *parm) +{ + char buf[400], *cpy; + int len; + + if (remote_debug) + { + if (format && *format) + len = strlen (format); + else + return; /* empty input */ + + if (parm && *parm) + len += strlen (parm); + + for (cpy = buf; *format;) + { + if (format[0] == '%' && format[1] == 's') /* include second string */ + { + format += 2; /* advance two chars instead of just one */ + while (parm && *parm) + *cpy++ = *parm++; + } + else + *cpy++ = *format++; + } + *cpy = '\0'; + gdb_puts (buf); + } +} + +static unsigned char * +strcpy (unsigned char *dest, const unsigned char *src) +{ + unsigned char *ret = dest; + + if (dest && src) + { + while (*src) + *dest++ = *src++; + *dest = 0; + } + return ret; +} + +static int +strlen (const unsigned char *src) +{ + int ret; + + for (ret = 0; *src; src++) + ret++; + + return ret; +} + +#if 0 +void +exit (code) + int code; +{ + _exit (code); +} + +int +atexit (void *p) +{ + return 0; +} + +void +abort (void) +{ + _exit (1); +} +#endif diff --git a/contrib/gdb-7/gdb/stubs/m68k-stub.c b/contrib/gdb-7/gdb/stubs/m68k-stub.c new file mode 100644 index 0000000000..4ef4069bc3 --- /dev/null +++ b/contrib/gdb-7/gdb/stubs/m68k-stub.c @@ -0,0 +1,1098 @@ +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. The breakpoint instruction + * is hardwired to trap #1 because not to do so is a compatibility problem-- + * there either should be a standard breakpoint instruction, or the protocol + * should be extended to provide some means to communicate which breakpoint + * instruction is in use (or have the stub insert the breakpoint). + * + * Some explanation is probably necessary to explain how exceptions are + * handled. When an exception is encountered the 68000 pushes the current + * program counter and status register onto the supervisor stack and then + * transfers execution to a location specified in it's vector table. + * The handlers for the exception vectors are hardwired to jmp to an address + * given by the relation: (exception - 256) * 6. These are decending + * addresses starting from -6, -12, -18, ... By allowing 6 bytes for + * each entry, a jsr, jmp, bsr, ... can be used to enter the exception + * handler. Using a jsr to handle an exception has an added benefit of + * allowing a single handler to service several exceptions and use the + * return address as the key differentiation. The vector number can be + * computed from the return address by [ exception = (addr + 1530) / 6 ]. + * The sole purpose of the routine _catchException is to compute the + * exception number and push it on the stack in place of the return address. + * The external function exceptionHandler() is + * used to attach a specific handler to a specific m68k exception. + * For 68020 machines, the ability to have a return address around just + * so the vector can be determined is not necessary because the '020 pushes an + * extra word onto the stack containing the vector offset + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*ExceptionHook)(int); /* pointer to function with int parm */ +typedef void (*Function)(); /* pointer to a function */ + +extern void putDebugChar(); /* write a single character */ +extern int getDebugChar(); /* read and return a single char */ + +extern Function exceptionHandler(); /* assign an exception handler */ +extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */ + +/************************/ +/* FORWARD DECLARATIONS */ +/************************/ +static void +initializeRemcomErrorFrame (); + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const char hexchars[]="0123456789abcdef"; + +/* there are 180 bytes of registers on a 68020 w/68881 */ +/* many of the fpa registers are 12 byte (96 bit) registers */ +#define NUMREGBYTES 180 +enum regnames {D0,D1,D2,D3,D4,D5,D6,D7, + A0,A1,A2,A3,A4,A5,A6,A7, + PS,PC, + FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7, + FPCONTROL,FPSTATUS,FPIADDR + }; + + +/* We keep a whole frame cache here. "Why?", I hear you cry, "doesn't + GDB handle that sort of thing?" Well, yes, I believe the only + reason for this cache is to save and restore floating point state + (fsave/frestore). A cleaner way to do this would be to make the + fsave data part of the registers which GDB deals with like any + other registers. This should not be a performance problem if the + ability to read individual registers is added to the protocol. */ + +typedef struct FrameStruct +{ + struct FrameStruct *previous; + int exceptionPC; /* pc value when this frame created */ + int exceptionVector; /* cpu vector causing exception */ + short frameSize; /* size of cpu frame in words */ + short sr; /* for 68000, this not always sr */ + int pc; + short format; + int fsaveHeader; + int morejunk[0]; /* exception frame, fp save... */ +} Frame; + +#define FRAMESIZE 500 +int gdbFrameStack[FRAMESIZE]; +static Frame *lastFrame; + +/* + * these should not be static cuz they can be used outside this module + */ +int registers[NUMREGBYTES/4]; +int superStack; + +#define STACKSIZE 10000 +int remcomStack[STACKSIZE/sizeof(int)]; +static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; + +/* + * In many cases, the system will want to continue exception processing + * when a continue command is given. + * oldExceptionHook is a function to invoke in this case. + */ + +static ExceptionHook oldExceptionHook; + +#ifdef mc68020 +/* the size of the exception stack on the 68020 varies with the type of + * exception. The following table is the number of WORDS used + * for each exception format. + */ +const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 }; +#endif + +#ifdef mc68332 +static const short exceptionSize[] = { 4,4,6,4,4,4,4,4,4,4,4,4,16,4,4,4 }; +#endif + +/************* jump buffer used for setjmp/longjmp **************************/ +jmp_buf remcomEnv; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* */ + +#ifdef __HAVE_68881__ +/* do an fsave, then remember the address to begin a restore from */ +#define SAVE_FP_REGS() asm(" fsave a0@-"); \ + asm(" fmovemx fp0-fp7,_registers+72"); \ + asm(" fmoveml fpcr/fpsr/fpi,_registers+168"); +#define RESTORE_FP_REGS() \ +asm(" \n\ + fmoveml _registers+168,fpcr/fpsr/fpi \n\ + fmovemx _registers+72,fp0-fp7 \n\ + cmpl #-1,a0@ | skip frestore flag set ? \n\ + beq skip_frestore \n\ + frestore a0@+ \n\ +skip_frestore: \n\ +"); + +#else +#define SAVE_FP_REGS() +#define RESTORE_FP_REGS() +#endif /* __HAVE_68881__ */ + +void return_to_super(); +void return_to_user(); + +asm(" +.text +.globl _return_to_super +_return_to_super: + movel _registers+60,sp /* get new stack pointer */ + movel _lastFrame,a0 /* get last frame info */ + bra return_to_any + +.globl _return_to_user +_return_to_user: + movel _registers+60,a0 /* get usp */ + movel a0,usp /* set usp */ + movel _superStack,sp /* get original stack pointer */ + +return_to_any: + movel _lastFrame,a0 /* get last frame info */ + movel a0@+,_lastFrame /* link in previous frame */ + addql #8,a0 /* skip over pc, vector#*/ + movew a0@+,d0 /* get # of words in cpu frame */ + addw d0,a0 /* point to end of data */ + addw d0,a0 /* point to end of data */ + movel a0,a1 +# +# copy the stack frame + subql #1,d0 +copyUserLoop: + movew a1@-,sp@- + dbf d0,copyUserLoop +"); + RESTORE_FP_REGS() + asm(" moveml _registers,d0-d7/a0-a6"); + asm(" rte"); /* pop and go! */ + +#define DISABLE_INTERRUPTS() asm(" oriw #0x0700,sr"); +#define BREAKPOINT() asm(" trap #1"); + +/* this function is called immediately when a level 7 interrupt occurs */ +/* if the previous interrupt level was 7 then we're already servicing */ +/* this interrupt and an rte is in order to return to the debugger. */ +/* For the 68000, the offset for sr is 6 due to the jsr return address */ +asm(" +.text +.globl __debug_level7 +__debug_level7: + movew d0,sp@-"); +#if defined (mc68020) || defined (mc68332) +asm(" movew sp@(2),d0"); +#else +asm(" movew sp@(6),d0"); +#endif +asm(" andiw #0x700,d0 + cmpiw #0x700,d0 + beq _already7 + movew sp@+,d0 + bra __catchException +_already7: + movew sp@+,d0"); +#if !defined (mc68020) && !defined (mc68332) +asm(" lea sp@(4),sp"); /* pull off 68000 return address */ +#endif +asm(" rte"); + +extern void _catchException (); + +#if defined (mc68020) || defined (mc68332) +/* This function is called when a 68020 exception occurs. It saves + * all the cpu and fpcp regs in the _registers array, creates a frame on a + * linked list of frames which has the cpu and fpcp stack frames needed + * to properly restore the context of these processors, and invokes + * an exception handler (remcom_handler). + * + * stack on entry: stack on exit: + * N bytes of junk exception # MSWord + * Exception Format Word exception # MSWord + * Program counter LSWord + * Program counter MSWord + * Status Register + * + * + */ +asm(" +.text +.globl __catchException +__catchException:"); +DISABLE_INTERRUPTS(); +asm(" + moveml d0-d7/a0-a6,_registers /* save registers */ + movel _lastFrame,a0 /* last frame pointer */ +"); +SAVE_FP_REGS(); +asm(" + lea _registers,a5 /* get address of registers */ + movew sp@,d1 /* get status register */ + movew d1,a5@(66) /* save sr */ + movel sp@(2),a4 /* save pc in a4 for later use */ + movel a4,a5@(68) /* save pc in _regisers[] */ + +# +# figure out how many bytes in the stack frame + movew sp@(6),d0 /* get '020 exception format */ + movew d0,d2 /* make a copy of format word */ + andiw #0xf000,d0 /* mask off format type */ + rolw #5,d0 /* rotate into the low byte *2 */ + lea _exceptionSize,a1 + addw d0,a1 /* index into the table */ + movew a1@,d0 /* get number of words in frame */ + movew d0,d3 /* save it */ + subw d0,a0 /* adjust save pointer */ + subw d0,a0 /* adjust save pointer(bytes) */ + movel a0,a1 /* copy save pointer */ + subql #1,d0 /* predecrement loop counter */ +# +# copy the frame +saveFrameLoop: + movew sp@+,a1@+ + dbf d0,saveFrameLoop +# +# now that the stack has been clenaed, +# save the a7 in use at time of exception + movel sp,_superStack /* save supervisor sp */ + andiw #0x2000,d1 /* were we in supervisor mode ? */ + beq userMode + movel a7,a5@(60) /* save a7 */ + bra a7saveDone +userMode: + movel usp,a1 + movel a1,a5@(60) /* save user stack pointer */ +a7saveDone: + +# +# save size of frame + movew d3,a0@- + +# +# compute exception number + andl #0xfff,d2 /* mask off vector offset */ + lsrw #2,d2 /* divide by 4 to get vect num */ + movel d2,a0@- /* save it */ +# +# save pc causing exception + movel a4,a0@- +# +# save old frame link and set the new value + movel _lastFrame,a1 /* last frame pointer */ + movel a1,a0@- /* save pointer to prev frame */ + movel a0,_lastFrame + + movel d2,sp@- /* push exception num */ + movel _exceptionHook,a0 /* get address of handler */ + jbsr a0@ /* and call it */ + clrl sp@ /* replace exception num parm with frame ptr */ + jbsr __returnFromException /* jbsr, but never returns */ +"); +#else /* mc68000 */ +/* This function is called when an exception occurs. It translates the + * return address found on the stack into an exception vector # which + * is then handled by either handle_exception or a system handler. + * _catchException provides a front end for both. + * + * stack on entry: stack on exit: + * Program counter MSWord exception # MSWord + * Program counter LSWord exception # MSWord + * Status Register + * Return Address MSWord + * Return Address LSWord + */ +asm(" +.text +.globl __catchException +__catchException:"); +DISABLE_INTERRUPTS(); +asm(" + moveml d0-d7/a0-a6,_registers /* save registers */ + movel _lastFrame,a0 /* last frame pointer */ +"); +SAVE_FP_REGS(); +asm(" + lea _registers,a5 /* get address of registers */ + movel sp@+,d2 /* pop return address */ + addl #1530,d2 /* convert return addr to */ + divs #6,d2 /* exception number */ + extl d2 + + moveql #3,d3 /* assume a three word frame */ + + cmpiw #3,d2 /* bus error or address error ? */ + bgt normal /* if >3 then normal error */ + movel sp@+,a0@- /* copy error info to frame buff*/ + movel sp@+,a0@- /* these are never used */ + moveql #7,d3 /* this is a 7 word frame */ + +normal: + movew sp@+,d1 /* pop status register */ + movel sp@+,a4 /* pop program counter */ + movew d1,a5@(66) /* save sr */ + movel a4,a5@(68) /* save pc in _regisers[] */ + movel a4,a0@- /* copy pc to frame buffer */ + movew d1,a0@- /* copy sr to frame buffer */ + + movel sp,_superStack /* save supervisor sp */ + + andiw #0x2000,d1 /* were we in supervisor mode ? */ + beq userMode + movel a7,a5@(60) /* save a7 */ + bra saveDone +userMode: + movel usp,a1 /* save user stack pointer */ + movel a1,a5@(60) /* save user stack pointer */ +saveDone: + + movew d3,a0@- /* push frame size in words */ + movel d2,a0@- /* push vector number */ + movel a4,a0@- /* push exception pc */ + +# +# save old frame link and set the new value + movel _lastFrame,a1 /* last frame pointer */ + movel a1,a0@- /* save pointer to prev frame */ + movel a0,_lastFrame + + movel d2,sp@- /* push exception num */ + movel _exceptionHook,a0 /* get address of handler */ + jbsr a0@ /* and call it */ + clrl sp@ /* replace exception num parm with frame ptr */ + jbsr __returnFromException /* jbsr, but never returns */ +"); +#endif + + +/* + * remcomHandler is a front end for handle_exception. It moves the + * stack pointer into an area reserved for debugger use in case the + * breakpoint happened in supervisor mode. + */ +asm("_remcomHandler:"); +asm(" addl #4,sp"); /* pop off return address */ +asm(" movel sp@+,d0"); /* get the exception number */ +asm(" movel _stackPtr,sp"); /* move to remcom stack area */ +asm(" movel d0,sp@-"); /* push exception onto stack */ +asm(" jbsr _handle_exception"); /* this never returns */ +asm(" rts"); /* return */ + +void +_returnFromException (Frame * frame) +{ + /* if no passed in frame, use the last one */ + if (!frame) + { + frame = lastFrame; + frame->frameSize = 4; + frame->format = 0; + frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info */ + } + +#if !defined (mc68020) && !defined (mc68332) + /* a 68000 cannot use the internal info pushed onto a bus error + * or address error frame when doing an RTE so don't put this info + * onto the stack or the stack will creep every time this happens. + */ + frame->frameSize = 3; +#endif + + /* throw away any frames in the list after this frame */ + lastFrame = frame; + + frame->sr = registers[(int) PS]; + frame->pc = registers[(int) PC]; + + if (registers[(int) PS] & 0x2000) + { + /* return to supervisor mode... */ + return_to_super (); + } + else + { /* return to user mode */ + return_to_user (); + } +} + +int +hex (ch) + char ch; +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +/* scan for the sequence $# */ + +unsigned char * +getpacket (void) +{ + unsigned char *buffer = &remcomInBuffer[0]; + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + while (1) + { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar ()) != '$') + ; + + retry: + checksum = 0; + xmitcsum = -1; + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX - 1) + { + ch = getDebugChar (); + if (ch == '$') + goto retry; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + ch = getDebugChar (); + xmitcsum = hex (ch) << 4; + ch = getDebugChar (); + xmitcsum += hex (ch); + + if (checksum != xmitcsum) + { + if (remote_debug) + { + fprintf (stderr, + "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + putDebugChar ('-'); /* failed checksum */ + } + else + { + putDebugChar ('+'); /* successful transfer */ + + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + return &buffer[3]; + } + + return &buffer[0]; + } + } + } +} + +/* send the packet in buffer. */ + +void +putpacket (buffer) + char *buffer; +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum % 16]); + + } + while (getDebugChar () != '+'); + +} + +void +debug_error (format, parm) + char *format; + char *parm; +{ + if (remote_debug) + fprintf (stderr, format, parm); +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +char * +mem2hex (mem, buf, count) + char *mem; + char *buf; + int count; +{ + int i; + unsigned char ch; + for (i = 0; i < count; i++) + { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return (buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +char * +hex2mem (buf, mem, count) + char *buf; + char *mem; + int count; +{ + int i; + unsigned char ch; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + *mem++ = ch; + } + return (mem); +} + +/* a bus error has occurred, perform a longjmp + to return execution and allow handling of the error */ + +void +handle_buserror () +{ + longjmp (remcomEnv, 1); +} + +/* this function takes the 68000 exception number and attempts to + translate this number into a unix compatible signal value */ +int +computeSignal (exceptionVector) + int exceptionVector; +{ + int sigval; + switch (exceptionVector) + { + case 2: + sigval = 10; + break; /* bus error */ + case 3: + sigval = 10; + break; /* address error */ + case 4: + sigval = 4; + break; /* illegal instruction */ + case 5: + sigval = 8; + break; /* zero divide */ + case 6: + sigval = 8; + break; /* chk instruction */ + case 7: + sigval = 8; + break; /* trapv instruction */ + case 8: + sigval = 11; + break; /* privilege violation */ + case 9: + sigval = 5; + break; /* trace trap */ + case 10: + sigval = 4; + break; /* line 1010 emulator */ + case 11: + sigval = 4; + break; /* line 1111 emulator */ + + /* Coprocessor protocol violation. Using a standard MMU or FPU + this cannot be triggered by software. Call it a SIGBUS. */ + case 13: + sigval = 10; + break; + + case 31: + sigval = 2; + break; /* interrupt */ + case 33: + sigval = 5; + break; /* breakpoint */ + + /* This is a trap #8 instruction. Apparently it is someone's software + convention for some sort of SIGFPE condition. Whose? How many + people are being screwed by having this code the way it is? + Is there a clean solution? */ + case 40: + sigval = 8; + break; /* floating point err */ + + case 48: + sigval = 8; + break; /* floating point err */ + case 49: + sigval = 8; + break; /* floating point err */ + case 50: + sigval = 8; + break; /* zero divide */ + case 51: + sigval = 8; + break; /* underflow */ + case 52: + sigval = 8; + break; /* operand error */ + case 53: + sigval = 8; + break; /* overflow */ + case 54: + sigval = 8; + break; /* NAN */ + default: + sigval = 7; /* "software generated" */ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToInt (char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex (**ptr); + if (hexValue >= 0) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* + * This function does all command procesing for interfacing to gdb. + */ +void +handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length; + char *ptr; + int newPC; + Frame *frame; + + if (remote_debug) + printf ("vector=%d, sr=0x%x, pc=0x%x\n", + exceptionVector, registers[PS], registers[PC]); + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + + putpacket (remcomOutBuffer); + + stepping = 0; + + while (1 == 1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + switch (*ptr++) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (char *) registers, NUMREGBYTES); + strcpy (remcomOutBuffer, "OK"); + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + if (setjmp (remcomEnv) == 0) + { + exceptionHandler (2, handle_buserror); + + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem2hex ((char *) addr, remcomOutBuffer, length); + } + + if (ptr) + { + strcpy (remcomOutBuffer, "E01"); + } + } + else + { + exceptionHandler (2, _catchException); + strcpy (remcomOutBuffer, "E03"); + debug_error ("bus error"); + } + + /* restore handler for bus error */ + exceptionHandler (2, _catchException); + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M': + if (setjmp (remcomEnv) == 0) + { + exceptionHandler (2, handle_buserror); + + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + hex2mem (ptr, (char *) addr, length); + ptr = 0; + strcpy (remcomOutBuffer, "OK"); + } + if (ptr) + { + strcpy (remcomOutBuffer, "E02"); + } + } + else + { + exceptionHandler (2, _catchException); + strcpy (remcomOutBuffer, "E03"); + debug_error ("bus error"); + } + + /* restore handler for bus error */ + exceptionHandler (2, _catchException); + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 's': + stepping = 1; + case 'c': + /* try to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + newPC = registers[PC]; + + /* clear the trace bit */ + registers[PS] &= 0x7fff; + + /* set the trace bit if we're stepping */ + if (stepping) + registers[PS] |= 0x8000; + + /* + * look for newPC in the linked list of exception frames. + * if it is found, use the old frame it. otherwise, + * fake up a dummy frame in returnFromException(). + */ + if (remote_debug) + printf ("new pc = 0x%x\n", newPC); + frame = lastFrame; + while (frame) + { + if (remote_debug) + printf ("frame at 0x%x has pc=0x%x, except#=%d\n", + frame, frame->exceptionPC, frame->exceptionVector); + if (frame->exceptionPC == newPC) + break; /* bingo! a match */ + /* + * for a breakpoint instruction, the saved pc may + * be off by two due to re-executing the instruction + * replaced by the trap instruction. Check for this. + */ + if ((frame->exceptionVector == 33) && + (frame->exceptionPC == (newPC + 2))) + break; + if (frame == frame->previous) + { + frame = 0; /* no match found */ + break; + } + frame = frame->previous; + } + + /* + * If we found a match for the PC AND we are not returning + * as a result of a breakpoint (33), + * trace exception (9), nmi (31), jmp to + * the old exception handler as if this code never ran. + */ + if (frame) + { + if ((frame->exceptionVector != 9) && + (frame->exceptionVector != 31) && + (frame->exceptionVector != 33)) + { + /* + * invoke the previous handler. + */ + if (oldExceptionHook) + (*oldExceptionHook) (frame->exceptionVector); + newPC = registers[PC]; /* pc may have changed */ + if (newPC != frame->exceptionPC) + { + if (remote_debug) + printf ("frame at 0x%x has pc=0x%x, except#=%d\n", + frame, frame->exceptionPC, + frame->exceptionVector); + /* re-use the last frame, we're skipping it (longjump?) */ + frame = (Frame *) 0; + _returnFromException (frame); /* this is a jump */ + } + } + } + + /* if we couldn't find a frame, create one */ + if (frame == 0) + { + frame = lastFrame - 1; + + /* by using a bunch of print commands with breakpoints, + it's possible for the frame stack to creep down. If it creeps + too far, give up and reset it to the top. Normal use should + not see this happen. + */ + if ((unsigned int) (frame - 2) < (unsigned int) &gdbFrameStack) + { + initializeRemcomErrorFrame (); + frame = lastFrame; + } + frame->previous = lastFrame; + lastFrame = frame; + frame = 0; /* null so _return... will properly initialize it */ + } + + _returnFromException (frame); /* this is a jump */ + + break; + + /* kill the program */ + case 'k': /* do nothing */ + break; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + + +void +initializeRemcomErrorFrame (void) +{ + lastFrame = ((Frame *) & gdbFrameStack[FRAMESIZE - 1]) - 1; + lastFrame->previous = lastFrame; +} + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void +set_debug_traps () +{ + extern void _debug_level7 (); + extern void remcomHandler (); + int exception; + + initializeRemcomErrorFrame (); + stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + + for (exception = 2; exception <= 23; exception++) + exceptionHandler (exception, _catchException); + + /* level 7 interrupt */ + exceptionHandler (31, _debug_level7); + + /* breakpoint exception (trap #1) */ + exceptionHandler (33, _catchException); + + /* This is a trap #8 instruction. Apparently it is someone's software + convention for some sort of SIGFPE condition. Whose? How many + people are being screwed by having this code the way it is? + Is there a clean solution? */ + exceptionHandler (40, _catchException); + + /* 48 to 54 are floating point coprocessor errors */ + for (exception = 48; exception <= 54; exception++) + exceptionHandler (exception, _catchException); + + if (oldExceptionHook != remcomHandler) + { + oldExceptionHook = exceptionHook; + exceptionHook = remcomHandler; + } + + initialized = 1; + +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint () +{ + if (initialized) + BREAKPOINT (); +} diff --git a/contrib/gdb-7/gdb/stubs/sh-stub.c b/contrib/gdb-7/gdb/stubs/sh-stub.c new file mode 100644 index 0000000000..76c98a5e8a --- /dev/null +++ b/contrib/gdb-7/gdb/stubs/sh-stub.c @@ -0,0 +1,1583 @@ +/* sh-stub.c -- debugging stub for the Renesas-SH. + + NOTE!! This code has to be compiled with optimization, otherwise the + function inlining which generates the exception handlers won't work. + +*/ + +/* This is originally based on an m68k software stub written by Glenn + Engel at HP, but has changed quite a bit. + + Modifications for the SH by Ben Lee and Steve Chamberlain + +*/ + +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + + +/* Remote communication protocol. + + A debug packet whose contents are + is encapsulated for transmission in the form: + + $ # CSUM1 CSUM2 + + must be ASCII alphanumeric and cannot include characters + '$' or '#'. If starts with two characters followed by + ':', then the existing stubs interpret this as a sequence number. + + CSUM1 and CSUM2 are ascii hex representation of an 8-bit + checksum of , the most significant nibble is sent first. + the hex digits 0-9,a-f are used. + + Receiver responds with: + + + - if CSUM is correct and ready for next packet + - - if CSUM is incorrect + + is as follows: + All values are encoded in ascii hex digits. + + Request Packet + + read registers g + reply XX....X Each byte of register data + is described by two hex digits. + Registers are in the internal order + for GDB, and the bytes in a register + are in the same order the machine uses. + or ENN for an error. + + write regs GXX..XX Each byte of register data + is described by two hex digits. + reply OK for success + ENN for an error + + write reg Pn...=r... Write register n... with value r..., + which contains two hex digits for each + byte in the register (target byte + order). + reply OK for success + ENN for an error + (not supported by all stubs). + + read mem mAA..AA,LLLL AA..AA is address, LLLL is length. + reply XX..XX XX..XX is mem contents + Can be fewer bytes than requested + if able to read only part of the data. + or ENN NN is errno + + write mem MAA..AA,LLLL:XX..XX + AA..AA is address, + LLLL is number of bytes, + XX..XX is data + reply OK for success + ENN for an error (this includes the case + where only part of the data was + written). + + cont cAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + step sAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + last signal ? Reply the current reason for stopping. + This is the same reply as is generated + for step or cont : SAA where AA is the + signal number. + + There is no immediate reply to step or cont. + The reply comes when the machine stops. + It is SAA AA is the "signal number" + + or... TAAn...:r...;n:r...;n...:r...; + AA = signal number + n... = register number + r... = register contents + or... WAA The process exited, and AA is + the exit status. This is only + applicable for certains sorts of + targets. + kill request k + + toggle debug d toggle debug flag (see 386 & 68k stubs) + reset r reset -- see sparc stub. + reserved On other requests, the stub should + ignore the request and send an empty + response ($#). This way + we can extend the protocol and GDB + can tell whether the stub it is + talking to uses the old or the new. + search tAA:PP,MM Search backwards starting at address + AA for a match with pattern PP and + mask MM. PP and MM are 4 bytes. + Not supported by all stubs. + + general query qXXXX Request info about XXXX. + general set QXXXX=yyyy Set value of XXXX to yyyy. + query sect offs qOffsets Get section offsets. Reply is + Text=xxx;Data=yyy;Bss=zzz + console output Otext Send text to stdout. Only comes from + remote target. + + Responses can be run-length encoded to save space. A '*' means that + the next character is an ASCII encoding giving a repeat count which + stands for that many repititions of the character preceding the '*'. + The encoding is n+29, yielding a printable character where n >=3 + (which is where rle starts to win). Don't use an n > 126. + + So + "0* " means the same as "0000". */ + +#include +#include + +/* Renesas SH architecture instruction encoding masks */ + +#define COND_BR_MASK 0xff00 +#define UCOND_DBR_MASK 0xe000 +#define UCOND_RBR_MASK 0xf0df +#define TRAPA_MASK 0xff00 + +#define COND_DISP 0x00ff +#define UCOND_DISP 0x0fff +#define UCOND_REG 0x0f00 + +/* Renesas SH instruction opcodes */ + +#define BF_INSTR 0x8b00 +#define BT_INSTR 0x8900 +#define BRA_INSTR 0xa000 +#define BSR_INSTR 0xb000 +#define JMP_INSTR 0x402b +#define JSR_INSTR 0x400b +#define RTS_INSTR 0x000b +#define RTE_INSTR 0x002b +#define TRAPA_INSTR 0xc300 +#define SSTEP_INSTR 0xc3ff + +/* Renesas SH processor register masks */ + +#define T_BIT_MASK 0x0001 + +/* + * BUFMAX defines the maximum number of characters in inbound/outbound + * buffers. At least NUMREGBYTES*2 are needed for register packets. + */ +#define BUFMAX 1024 + +/* + * Number of bytes for registers + */ +#define NUMREGBYTES 112 /* 92 */ + +/* + * typedef + */ +typedef void (*Function) (); + +/* + * Forward declarations + */ + +static int hex (char); +static char *mem2hex (char *, char *, int); +static char *hex2mem (char *, char *, int); +static int hexToInt (char **, int *); +static unsigned char *getpacket (void); +static void putpacket (char *); +static void handle_buserror (void); +static int computeSignal (int exceptionVector); +static void handle_exception (int exceptionVector); +void init_serial(); + +void putDebugChar (char); +char getDebugChar (void); + +/* These are in the file but in asm statements so the compiler can't see them */ +void catch_exception_4 (void); +void catch_exception_6 (void); +void catch_exception_9 (void); +void catch_exception_10 (void); +void catch_exception_11 (void); +void catch_exception_32 (void); +void catch_exception_33 (void); +void catch_exception_255 (void); + + + +#define catch_exception_random catch_exception_255 /* Treat all odd ones like 255 */ + +void breakpoint (void); + + +#define init_stack_size 8*1024 /* if you change this you should also modify BINIT */ +#define stub_stack_size 8*1024 + +int init_stack[init_stack_size] __attribute__ ((section ("stack"))) = {0}; +int stub_stack[stub_stack_size] __attribute__ ((section ("stack"))) = {0}; + + +void INIT (); +void BINIT (); + +#define CPU_BUS_ERROR_VEC 9 +#define DMA_BUS_ERROR_VEC 10 +#define NMI_VEC 11 +#define INVALID_INSN_VEC 4 +#define INVALID_SLOT_VEC 6 +#define TRAP_VEC 32 +#define IO_VEC 33 +#define USER_VEC 255 + + + +char in_nmi; /* Set when handling an NMI, so we don't reenter */ +int dofault; /* Non zero, bus errors will raise exception */ + +int *stub_sp; + +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ +int remote_debug; + +/* jump buffer used for setjmp/longjmp */ +jmp_buf remcomEnv; + +enum regnames + { + R0, R1, R2, R3, R4, R5, R6, R7, + R8, R9, R10, R11, R12, R13, R14, + R15, PC, PR, GBR, VBR, MACH, MACL, SR, + TICKS, STALLS, CYCLES, INSTS, PLR + }; + +typedef struct + { + short *memAddr; + short oldInstr; + } +stepData; + +int registers[NUMREGBYTES / 4]; +stepData instrBuffer; +char stepped; +static const char hexchars[] = "0123456789abcdef"; +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +char highhex(int x) +{ + return hexchars[(x >> 4) & 0xf]; +} + +char lowhex(int x) +{ + return hexchars[x & 0xf]; +} + +/* + * Assembly macros + */ + +#define BREAKPOINT() asm("trapa #0x20"::); + + +/* + * Routines to handle hex data + */ + +static int +hex (char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* convert the memory, pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +static char * +mem2hex (char *mem, char *buf, int count) +{ + int i; + int ch; + for (i = 0; i < count; i++) + { + ch = *mem++; + *buf++ = highhex (ch); + *buf++ = lowhex (ch); + } + *buf = 0; + return (buf); +} + +/* convert the hex array pointed to by buf into binary, to be placed in mem */ +/* return a pointer to the character after the last byte written */ + +static char * +hex2mem (char *buf, char *mem, int count) +{ + int i; + unsigned char ch; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + *mem++ = ch; + } + return (mem); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +static int +hexToInt (char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex (**ptr); + if (hexValue >= 0) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* + * Routines to get and put packets + */ + +/* scan for the sequence $# */ + +char * +getpacket (void) +{ + unsigned char *buffer = &remcomInBuffer[0]; + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + while (1) + { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar ()) != '$') + ; + +retry: + checksum = 0; + xmitcsum = -1; + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX - 1) + { + ch = getDebugChar (); + if (ch == '$') + goto retry; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + ch = getDebugChar (); + xmitcsum = hex (ch) << 4; + ch = getDebugChar (); + xmitcsum += hex (ch); + + if (checksum != xmitcsum) + { + putDebugChar ('-'); /* failed checksum */ + } + else + { + putDebugChar ('+'); /* successful transfer */ + + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + return &buffer[3]; + } + + return &buffer[0]; + } + } + } +} + + +/* send the packet in buffer. */ + +static void +putpacket (char *buffer) +{ + int checksum; + int count; + + /* $#. */ + do + { + char *src = buffer; + putDebugChar ('$'); + checksum = 0; + + while (*src) + { + int runlen; + + /* Do run length encoding */ + for (runlen = 0; runlen < 100; runlen ++) + { + if (src[0] != src[runlen]) + { + if (runlen > 3) + { + int encode; + /* Got a useful amount */ + putDebugChar (*src); + checksum += *src; + putDebugChar ('*'); + checksum += '*'; + checksum += (encode = runlen + ' ' - 4); + putDebugChar (encode); + src += runlen; + } + else + { + putDebugChar (*src); + checksum += *src; + src++; + } + break; + } + } + } + + + putDebugChar ('#'); + putDebugChar (highhex(checksum)); + putDebugChar (lowhex(checksum)); + } + while (getDebugChar() != '+'); +} + + +/* a bus error has occurred, perform a longjmp + to return execution and allow handling of the error */ + +void +handle_buserror (void) +{ + longjmp (remcomEnv, 1); +} + +/* + * this function takes the SH-1 exception number and attempts to + * translate this number into a unix compatible signal value + */ +static int +computeSignal (int exceptionVector) +{ + int sigval; + switch (exceptionVector) + { + case INVALID_INSN_VEC: + sigval = 4; + break; + case INVALID_SLOT_VEC: + sigval = 4; + break; + case CPU_BUS_ERROR_VEC: + sigval = 10; + break; + case DMA_BUS_ERROR_VEC: + sigval = 10; + break; + case NMI_VEC: + sigval = 2; + break; + + case TRAP_VEC: + case USER_VEC: + sigval = 5; + break; + + default: + sigval = 7; /* "software generated"*/ + break; + } + return (sigval); +} + +void +doSStep (void) +{ + short *instrMem; + int displacement; + int reg; + unsigned short opcode; + + instrMem = (short *) registers[PC]; + + opcode = *instrMem; + stepped = 1; + + if ((opcode & COND_BR_MASK) == BT_INSTR) + { + if (registers[SR] & T_BIT_MASK) + { + displacement = (opcode & COND_DISP) << 1; + if (displacement & 0x80) + displacement |= 0xffffff00; + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (registers[PC] + displacement + 4); + } + else + instrMem += 1; + } + else if ((opcode & COND_BR_MASK) == BF_INSTR) + { + if (registers[SR] & T_BIT_MASK) + instrMem += 1; + else + { + displacement = (opcode & COND_DISP) << 1; + if (displacement & 0x80) + displacement |= 0xffffff00; + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (registers[PC] + displacement + 4); + } + } + else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR) + { + displacement = (opcode & UCOND_DISP) << 1; + if (displacement & 0x0800) + displacement |= 0xfffff000; + + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (registers[PC] + displacement + 4); + } + else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR) + { + reg = (char) ((opcode & UCOND_REG) >> 8); + + instrMem = (short *) registers[reg]; + } + else if (opcode == RTS_INSTR) + instrMem = (short *) registers[PR]; + else if (opcode == RTE_INSTR) + instrMem = (short *) registers[15]; + else if ((opcode & TRAPA_MASK) == TRAPA_INSTR) + instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2); + else + instrMem += 1; + + instrBuffer.memAddr = instrMem; + instrBuffer.oldInstr = *instrMem; + *instrMem = SSTEP_INSTR; +} + + +/* Undo the effect of a previous doSStep. If we single stepped, + restore the old instruction. */ + +void +undoSStep (void) +{ + if (stepped) + { short *instrMem; + instrMem = instrBuffer.memAddr; + *instrMem = instrBuffer.oldInstr; + } + stepped = 0; +} + +/* +This function does all exception handling. It only does two things - +it figures out why it was called and tells gdb, and then it reacts +to gdb's requests. + +When in the monitor mode we talk a human on the serial line rather than gdb. + +*/ + + +void +gdb_handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length; + char *ptr; + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = highhex(sigval); + remcomOutBuffer[2] = lowhex (sigval); + remcomOutBuffer[3] = 0; + + putpacket (remcomOutBuffer); + + /* + * exception 255 indicates a software trap + * inserted in place of code ... so back up + * PC by one instruction, since this instruction + * will later be replaced by its original one! + */ + if (exceptionVector == 0xff + || exceptionVector == 0x20) + registers[PC] -= 2; + + /* + * Do the thangs needed to undo + * any stepping we may have done! + */ + undoSStep (); + + stepping = 0; + + while (1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + + switch (*ptr++) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = highhex (sigval); + remcomOutBuffer[2] = lowhex (sigval); + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (char *) registers, NUMREGBYTES); + strcpy (remcomOutBuffer, "OK"); + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + if (setjmp (remcomEnv) == 0) + { + dofault = 0; + /* TRY, TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem2hex ((char *) addr, remcomOutBuffer, length); + } + if (ptr) + strcpy (remcomOutBuffer, "E01"); + } + else + strcpy (remcomOutBuffer, "E03"); + + /* restore handler for bus error */ + dofault = 1; + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M': + if (setjmp (remcomEnv) == 0) + { + dofault = 0; + + /* TRY, TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + hex2mem (ptr, (char *) addr, length); + ptr = 0; + strcpy (remcomOutBuffer, "OK"); + } + if (ptr) + strcpy (remcomOutBuffer, "E02"); + } + else + strcpy (remcomOutBuffer, "E03"); + + /* restore handler for bus error */ + dofault = 1; + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 's': + stepping = 1; + case 'c': + { + /* tRY, to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + if (stepping) + doSStep (); + } + return; + break; + + /* kill the program */ + case 'k': /* do nothing */ + break; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + + +#define GDBCOOKIE 0x5ac +static int ingdbmode; +/* We've had an exception - choose to go into the monitor or + the gdb stub */ +void handle_exception(int exceptionVector) +{ +#ifdef MONITOR + if (ingdbmode != GDBCOOKIE) + monitor_handle_exception (exceptionVector); + else +#endif + gdb_handle_exception (exceptionVector); + +} + +void +gdb_mode (void) +{ + ingdbmode = GDBCOOKIE; + breakpoint(); +} +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint (void) +{ + BREAKPOINT (); +} + +/**** Processor-specific routines start here ****/ +/**** Processor-specific routines start here ****/ +/**** Processor-specific routines start here ****/ + +/* Note: + + The Renesas SH family uses two exception architectures: + + SH1 & SH2: + + These processors utilize an exception vector table. + Exceptions are vectored to the address stored at VBR + (exception_num * 4) + + SH3, SH3E, & SH4: + + These processors have fixed entry points relative to the VBR for + various exception classes. +*/ + +#if defined(__sh1__) || defined(__sh2__) + +/* SH1/SH2 exception vector table format */ + +typedef struct + { + void (*func_cold) (); + int *stack_cold; + void (*func_warm) (); + int *stack_warm; + void (*(handler[256 - 4])) (); + } +vec_type; + +/* vectable is the SH1/SH2 vector table. It must be at address 0 + or wherever your vbr points. */ + +const vec_type vectable = +{ + &BINIT, /* 0: Power-on reset PC */ + init_stack + init_stack_size, /* 1: Power-on reset SP */ + &BINIT, /* 2: Manual reset PC */ + init_stack + init_stack_size, /* 3: Manual reset SP */ +{ + &catch_exception_4, /* 4: General invalid instruction */ + &catch_exception_random, /* 5: Reserved for system */ + &catch_exception_6, /* 6: Invalid slot instruction */ + &catch_exception_random, /* 7: Reserved for system */ + &catch_exception_random, /* 8: Reserved for system */ + &catch_exception_9, /* 9: CPU bus error */ + &catch_exception_10, /* 10: DMA bus error */ + &catch_exception_11, /* 11: NMI */ + &catch_exception_random, /* 12: User break */ + &catch_exception_random, /* 13: Reserved for system */ + &catch_exception_random, /* 14: Reserved for system */ + &catch_exception_random, /* 15: Reserved for system */ + &catch_exception_random, /* 16: Reserved for system */ + &catch_exception_random, /* 17: Reserved for system */ + &catch_exception_random, /* 18: Reserved for system */ + &catch_exception_random, /* 19: Reserved for system */ + &catch_exception_random, /* 20: Reserved for system */ + &catch_exception_random, /* 21: Reserved for system */ + &catch_exception_random, /* 22: Reserved for system */ + &catch_exception_random, /* 23: Reserved for system */ + &catch_exception_random, /* 24: Reserved for system */ + &catch_exception_random, /* 25: Reserved for system */ + &catch_exception_random, /* 26: Reserved for system */ + &catch_exception_random, /* 27: Reserved for system */ + &catch_exception_random, /* 28: Reserved for system */ + &catch_exception_random, /* 29: Reserved for system */ + &catch_exception_random, /* 30: Reserved for system */ + &catch_exception_random, /* 31: Reserved for system */ + &catch_exception_32, /* 32: Trap instr (user vectors) */ + &catch_exception_33, /* 33: Trap instr (user vectors) */ + &catch_exception_random, /* 34: Trap instr (user vectors) */ + &catch_exception_random, /* 35: Trap instr (user vectors) */ + &catch_exception_random, /* 36: Trap instr (user vectors) */ + &catch_exception_random, /* 37: Trap instr (user vectors) */ + &catch_exception_random, /* 38: Trap instr (user vectors) */ + &catch_exception_random, /* 39: Trap instr (user vectors) */ + &catch_exception_random, /* 40: Trap instr (user vectors) */ + &catch_exception_random, /* 41: Trap instr (user vectors) */ + &catch_exception_random, /* 42: Trap instr (user vectors) */ + &catch_exception_random, /* 43: Trap instr (user vectors) */ + &catch_exception_random, /* 44: Trap instr (user vectors) */ + &catch_exception_random, /* 45: Trap instr (user vectors) */ + &catch_exception_random, /* 46: Trap instr (user vectors) */ + &catch_exception_random, /* 47: Trap instr (user vectors) */ + &catch_exception_random, /* 48: Trap instr (user vectors) */ + &catch_exception_random, /* 49: Trap instr (user vectors) */ + &catch_exception_random, /* 50: Trap instr (user vectors) */ + &catch_exception_random, /* 51: Trap instr (user vectors) */ + &catch_exception_random, /* 52: Trap instr (user vectors) */ + &catch_exception_random, /* 53: Trap instr (user vectors) */ + &catch_exception_random, /* 54: Trap instr (user vectors) */ + &catch_exception_random, /* 55: Trap instr (user vectors) */ + &catch_exception_random, /* 56: Trap instr (user vectors) */ + &catch_exception_random, /* 57: Trap instr (user vectors) */ + &catch_exception_random, /* 58: Trap instr (user vectors) */ + &catch_exception_random, /* 59: Trap instr (user vectors) */ + &catch_exception_random, /* 60: Trap instr (user vectors) */ + &catch_exception_random, /* 61: Trap instr (user vectors) */ + &catch_exception_random, /* 62: Trap instr (user vectors) */ + &catch_exception_random, /* 63: Trap instr (user vectors) */ + &catch_exception_random, /* 64: IRQ0 */ + &catch_exception_random, /* 65: IRQ1 */ + &catch_exception_random, /* 66: IRQ2 */ + &catch_exception_random, /* 67: IRQ3 */ + &catch_exception_random, /* 68: IRQ4 */ + &catch_exception_random, /* 69: IRQ5 */ + &catch_exception_random, /* 70: IRQ6 */ + &catch_exception_random, /* 71: IRQ7 */ + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_255}}; + +#define BCR (*(volatile short *)(0x05FFFFA0)) /* Bus control register */ +#define BAS (0x800) /* Byte access select */ +#define WCR1 (*(volatile short *)(0x05ffffA2)) /* Wait state control register */ + +asm ("_BINIT: mov.l L1,r15"); +asm ("bra _INIT"); +asm ("nop"); +asm ("L1: .long _init_stack + 8*1024*4"); +void +INIT (void) +{ + /* First turn on the ram */ + WCR1 = 0; /* Never sample wait */ + BCR = BAS; /* use lowbyte/high byte */ + + init_serial(); + +#ifdef MONITOR + reset_hook (); +#endif + + + in_nmi = 0; + dofault = 1; + stepped = 0; + + stub_sp = stub_stack + stub_stack_size; + breakpoint (); + + while (1) + ; +} + + +static void sr() +{ + + + /* Calling Reset does the same as pressing the button */ + asm (".global _Reset + .global _WarmReset +_Reset: +_WarmReset: + mov.l L_sp,r15 + bra _INIT + nop + .align 2 +L_sp: .long _init_stack + 8000"); + + asm("saveRegisters: + mov.l @(L_reg, pc), r0 + mov.l @r15+, r1 ! pop R0 + mov.l r2, @(0x08, r0) ! save R2 + mov.l r1, @r0 ! save R0 + mov.l @r15+, r1 ! pop R1 + mov.l r3, @(0x0c, r0) ! save R3 + mov.l r1, @(0x04, r0) ! save R1 + mov.l r4, @(0x10, r0) ! save R4 + mov.l r5, @(0x14, r0) ! save R5 + mov.l r6, @(0x18, r0) ! save R6 + mov.l r7, @(0x1c, r0) ! save R7 + mov.l r8, @(0x20, r0) ! save R8 + mov.l r9, @(0x24, r0) ! save R9 + mov.l r10, @(0x28, r0) ! save R10 + mov.l r11, @(0x2c, r0) ! save R11 + mov.l r12, @(0x30, r0) ! save R12 + mov.l r13, @(0x34, r0) ! save R13 + mov.l r14, @(0x38, r0) ! save R14 + mov.l @r15+, r4 ! save arg to handleException + add #8, r15 ! hide PC/SR values on stack + mov.l r15, @(0x3c, r0) ! save R15 + add #-8, r15 ! save still needs old SP value + add #92, r0 ! readjust register pointer + mov r15, r2 + add #4, r2 + mov.l @r2, r2 ! R2 has SR + mov.l @r15, r1 ! R1 has PC + mov.l r2, @-r0 ! save SR + sts.l macl, @-r0 ! save MACL + sts.l mach, @-r0 ! save MACH + stc.l vbr, @-r0 ! save VBR + stc.l gbr, @-r0 ! save GBR + sts.l pr, @-r0 ! save PR + mov.l @(L_stubstack, pc), r2 + mov.l @(L_hdl_except, pc), r3 + mov.l @r2, r15 + jsr @r3 + mov.l r1, @-r0 ! save PC + mov.l @(L_stubstack, pc), r0 + mov.l @(L_reg, pc), r1 + bra restoreRegisters + mov.l r15, @r0 ! save __stub_stack + + .align 2 +L_reg: + .long _registers +L_stubstack: + .long _stub_sp +L_hdl_except: + .long _handle_exception"); + +} + +static void rr() +{ +asm(" + .align 2 + .global _resume +_resume: + mov r4,r1 +restoreRegisters: + add #8, r1 ! skip to R2 + mov.l @r1+, r2 ! restore R2 + mov.l @r1+, r3 ! restore R3 + mov.l @r1+, r4 ! restore R4 + mov.l @r1+, r5 ! restore R5 + mov.l @r1+, r6 ! restore R6 + mov.l @r1+, r7 ! restore R7 + mov.l @r1+, r8 ! restore R8 + mov.l @r1+, r9 ! restore R9 + mov.l @r1+, r10 ! restore R10 + mov.l @r1+, r11 ! restore R11 + mov.l @r1+, r12 ! restore R12 + mov.l @r1+, r13 ! restore R13 + mov.l @r1+, r14 ! restore R14 + mov.l @r1+, r15 ! restore programs stack + mov.l @r1+, r0 + add #-8, r15 ! uncover PC/SR on stack + mov.l r0, @r15 ! restore PC onto stack + lds.l @r1+, pr ! restore PR + ldc.l @r1+, gbr ! restore GBR + ldc.l @r1+, vbr ! restore VBR + lds.l @r1+, mach ! restore MACH + lds.l @r1+, macl ! restore MACL + mov.l @r1, r0 + add #-88, r1 ! readjust reg pointer to R1 + mov.l r0, @(4, r15) ! restore SR onto stack+4 + mov.l r2, @-r15 + mov.l L_in_nmi, r0 + mov #0, r2 + mov.b r2, @r0 + mov.l @r15+, r2 + mov.l @r1+, r0 ! restore R0 + rte + mov.l @r1, r1 ! restore R1 + +"); +} + + +static __inline__ void code_for_catch_exception(int n) +{ + asm(" .globl _catch_exception_%O0" : : "i" (n) ); + asm(" _catch_exception_%O0:" :: "i" (n) ); + + asm(" add #-4, r15 ! reserve spot on stack "); + asm(" mov.l r1, @-r15 ! push R1 "); + + if (n == NMI_VEC) + { + /* Special case for NMI - make sure that they don't nest */ + asm(" mov.l r0, @-r15 ! push R0"); + asm(" mov.l L_in_nmi, r0"); + asm(" tas.b @r0 ! Fend off against addtnl NMIs"); + asm(" bt noNMI"); + asm(" mov.l @r15+, r0"); + asm(" mov.l @r15+, r1"); + asm(" add #4, r15"); + asm(" rte"); + asm(" nop"); + asm(".align 2"); + asm("L_in_nmi: .long _in_nmi"); + asm("noNMI:"); + } + else + { + + if (n == CPU_BUS_ERROR_VEC) + { + /* Exception 9 (bus errors) are disasbleable - so that you + can probe memory and get zero instead of a fault. + Because the vector table may be in ROM we don't revector + the interrupt like all the other stubs, we check in here + */ + asm("mov.l L_dofault,r1"); + asm("mov.l @r1,r1"); + asm("tst r1,r1"); + asm("bf faultaway"); + asm("bsr _handle_buserror"); + asm(".align 2"); + asm("L_dofault: .long _dofault"); + asm("faultaway:"); + } + asm(" mov #15<<4, r1 "); + asm(" ldc r1, sr ! disable interrupts "); + asm(" mov.l r0, @-r15 ! push R0 "); + } + + /* Prepare for saving context, we've already pushed r0 and r1, stick exception number + into the frame */ + asm(" mov r15, r0 "); + asm(" add #8, r0 "); + asm(" mov %0,r1" :: "i" (n) ); + asm(" extu.b r1,r1 "); + asm(" bra saveRegisters ! save register values "); + asm(" mov.l r1, @r0 ! save exception # "); +} + + +static void +exceptions (void) +{ + code_for_catch_exception (CPU_BUS_ERROR_VEC); + code_for_catch_exception (DMA_BUS_ERROR_VEC); + code_for_catch_exception (INVALID_INSN_VEC); + code_for_catch_exception (INVALID_SLOT_VEC); + code_for_catch_exception (NMI_VEC); + code_for_catch_exception (TRAP_VEC); + code_for_catch_exception (USER_VEC); + code_for_catch_exception (IO_VEC); +} + + + + + + +/* Support for Serial I/O using on chip uart */ + +#define SMR0 (*(volatile char *)(0x05FFFEC0)) /* Channel 0 serial mode register */ +#define BRR0 (*(volatile char *)(0x05FFFEC1)) /* Channel 0 bit rate register */ +#define SCR0 (*(volatile char *)(0x05FFFEC2)) /* Channel 0 serial control register */ +#define TDR0 (*(volatile char *)(0x05FFFEC3)) /* Channel 0 transmit data register */ +#define SSR0 (*(volatile char *)(0x05FFFEC4)) /* Channel 0 serial status register */ +#define RDR0 (*(volatile char *)(0x05FFFEC5)) /* Channel 0 receive data register */ + +#define SMR1 (*(volatile char *)(0x05FFFEC8)) /* Channel 1 serial mode register */ +#define BRR1 (*(volatile char *)(0x05FFFEC9)) /* Channel 1 bit rate register */ +#define SCR1 (*(volatile char *)(0x05FFFECA)) /* Channel 1 serial control register */ +#define TDR1 (*(volatile char *)(0x05FFFECB)) /* Channel 1 transmit data register */ +#define SSR1 (*(volatile char *)(0x05FFFECC)) /* Channel 1 serial status register */ +#define RDR1 (*(volatile char *)(0x05FFFECD)) /* Channel 1 receive data register */ + +/* + * Serial mode register bits + */ + +#define SYNC_MODE 0x80 +#define SEVEN_BIT_DATA 0x40 +#define PARITY_ON 0x20 +#define ODD_PARITY 0x10 +#define STOP_BITS_2 0x08 +#define ENABLE_MULTIP 0x04 +#define PHI_64 0x03 +#define PHI_16 0x02 +#define PHI_4 0x01 + +/* + * Serial control register bits + */ +#define SCI_TIE 0x80 /* Transmit interrupt enable */ +#define SCI_RIE 0x40 /* Receive interrupt enable */ +#define SCI_TE 0x20 /* Transmit enable */ +#define SCI_RE 0x10 /* Receive enable */ +#define SCI_MPIE 0x08 /* Multiprocessor interrupt enable */ +#define SCI_TEIE 0x04 /* Transmit end interrupt enable */ +#define SCI_CKE1 0x02 /* Clock enable 1 */ +#define SCI_CKE0 0x01 /* Clock enable 0 */ + +/* + * Serial status register bits + */ +#define SCI_TDRE 0x80 /* Transmit data register empty */ +#define SCI_RDRF 0x40 /* Receive data register full */ +#define SCI_ORER 0x20 /* Overrun error */ +#define SCI_FER 0x10 /* Framing error */ +#define SCI_PER 0x08 /* Parity error */ +#define SCI_TEND 0x04 /* Transmit end */ +#define SCI_MPB 0x02 /* Multiprocessor bit */ +#define SCI_MPBT 0x01 /* Multiprocessor bit transfer */ + + +/* + * Port B IO Register (PBIOR) + */ +#define PBIOR (*(volatile char *)(0x05FFFFC6)) +#define PB15IOR 0x8000 +#define PB14IOR 0x4000 +#define PB13IOR 0x2000 +#define PB12IOR 0x1000 +#define PB11IOR 0x0800 +#define PB10IOR 0x0400 +#define PB9IOR 0x0200 +#define PB8IOR 0x0100 +#define PB7IOR 0x0080 +#define PB6IOR 0x0040 +#define PB5IOR 0x0020 +#define PB4IOR 0x0010 +#define PB3IOR 0x0008 +#define PB2IOR 0x0004 +#define PB1IOR 0x0002 +#define PB0IOR 0x0001 + +/* + * Port B Control Register (PBCR1) + */ +#define PBCR1 (*(volatile short *)(0x05FFFFCC)) +#define PB15MD1 0x8000 +#define PB15MD0 0x4000 +#define PB14MD1 0x2000 +#define PB14MD0 0x1000 +#define PB13MD1 0x0800 +#define PB13MD0 0x0400 +#define PB12MD1 0x0200 +#define PB12MD0 0x0100 +#define PB11MD1 0x0080 +#define PB11MD0 0x0040 +#define PB10MD1 0x0020 +#define PB10MD0 0x0010 +#define PB9MD1 0x0008 +#define PB9MD0 0x0004 +#define PB8MD1 0x0002 +#define PB8MD0 0x0001 + +#define PB15MD PB15MD1|PB14MD0 +#define PB14MD PB14MD1|PB14MD0 +#define PB13MD PB13MD1|PB13MD0 +#define PB12MD PB12MD1|PB12MD0 +#define PB11MD PB11MD1|PB11MD0 +#define PB10MD PB10MD1|PB10MD0 +#define PB9MD PB9MD1|PB9MD0 +#define PB8MD PB8MD1|PB8MD0 + +#define PB_TXD1 PB11MD1 +#define PB_RXD1 PB10MD1 +#define PB_TXD0 PB9MD1 +#define PB_RXD0 PB8MD1 + +/* + * Port B Control Register (PBCR2) + */ +#define PBCR2 0x05FFFFCE +#define PB7MD1 0x8000 +#define PB7MD0 0x4000 +#define PB6MD1 0x2000 +#define PB6MD0 0x1000 +#define PB5MD1 0x0800 +#define PB5MD0 0x0400 +#define PB4MD1 0x0200 +#define PB4MD0 0x0100 +#define PB3MD1 0x0080 +#define PB3MD0 0x0040 +#define PB2MD1 0x0020 +#define PB2MD0 0x0010 +#define PB1MD1 0x0008 +#define PB1MD0 0x0004 +#define PB0MD1 0x0002 +#define PB0MD0 0x0001 + +#define PB7MD PB7MD1|PB7MD0 +#define PB6MD PB6MD1|PB6MD0 +#define PB5MD PB5MD1|PB5MD0 +#define PB4MD PB4MD1|PB4MD0 +#define PB3MD PB3MD1|PB3MD0 +#define PB2MD PB2MD1|PB2MD0 +#define PB1MD PB1MD1|PB1MD0 +#define PB0MD PB0MD1|PB0MD0 + + +#ifdef MHZ +#define BPS 32 * 9600 * MHZ / ( BAUD * 10) +#else +#define BPS 32 /* 9600 for 10 Mhz */ +#endif + +void handleError (char theSSR); + +void +nop (void) +{ + +} +void +init_serial (void) +{ + int i; + + /* Clear TE and RE in Channel 1's SCR */ + SCR1 &= ~(SCI_TE | SCI_RE); + + /* Set communication to be async, 8-bit data, no parity, 1 stop bit and use internal clock */ + + SMR1 = 0; + BRR1 = BPS; + + SCR1 &= ~(SCI_CKE1 | SCI_CKE0); + + /* let the hardware settle */ + + for (i = 0; i < 1000; i++) + nop (); + + /* Turn on in and out */ + SCR1 |= SCI_RE | SCI_TE; + + /* Set the PFC to make RXD1 (pin PB8) an input pin and TXD1 (pin PB9) an output pin */ + PBCR1 &= ~(PB_TXD1 | PB_RXD1); + PBCR1 |= PB_TXD1 | PB_RXD1; +} + + +int +getDebugCharReady (void) +{ + char mySSR; + mySSR = SSR1 & ( SCI_PER | SCI_FER | SCI_ORER ); + if ( mySSR ) + handleError ( mySSR ); + return SSR1 & SCI_RDRF ; +} + +char +getDebugChar (void) +{ + char ch; + char mySSR; + + while ( ! getDebugCharReady()) + ; + + ch = RDR1; + SSR1 &= ~SCI_RDRF; + + mySSR = SSR1 & (SCI_PER | SCI_FER | SCI_ORER); + + if (mySSR) + handleError (mySSR); + + return ch; +} + +int +putDebugCharReady (void) +{ + return (SSR1 & SCI_TDRE); +} + +void +putDebugChar (char ch) +{ + while (!putDebugCharReady()) + ; + + /* + * Write data into TDR and clear TDRE + */ + TDR1 = ch; + SSR1 &= ~SCI_TDRE; +} + +void +handleError (char theSSR) +{ + SSR1 &= ~(SCI_ORER | SCI_PER | SCI_FER); +} + +#endif diff --git a/contrib/gdb-7/gdb/stubs/sparc-stub.c b/contrib/gdb-7/gdb/stubs/sparc-stub.c new file mode 100644 index 0000000000..c12d4360a4 --- /dev/null +++ b/contrib/gdb-7/gdb/stubs/sparc-stub.c @@ -0,0 +1,778 @@ +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for SPARC by Stu Grossman, Cygnus Support. + * + * This code has been extensively tested on the Fujitsu SPARClite demo board. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ + +extern void putDebugChar(); /* write a single character */ +extern int getDebugChar(); /* read and return a single char */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 2048 + +static int initialized = 0; /* !0 means we've been initialized */ + +static void set_mem_fault_trap(); + +static const char hexchars[]="0123456789abcdef"; + +#define NUMREGS 72 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) +enum regnames {G0, G1, G2, G3, G4, G5, G6, G7, + O0, O1, O2, O3, O4, O5, SP, O7, + L0, L1, L2, L3, L4, L5, L6, L7, + I0, I1, I2, I3, I4, I5, FP, I7, + + F0, F1, F2, F3, F4, F5, F6, F7, + F8, F9, F10, F11, F12, F13, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, + F24, F25, F26, F27, F28, F29, F30, F31, + Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR }; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* */ + +extern void trap_low(); + +asm(" + .reserve trapstack, 1000 * 4, \"bss\", 8 + + .data + .align 4 + +in_trap_handler: + .word 0 + + .text + .align 4 + +! This function is called when any SPARC trap (except window overflow or +! underflow) occurs. It makes sure that the invalid register window is still +! available before jumping into C code. It will also restore the world if you +! return from handle_exception. + + .globl _trap_low +_trap_low: + mov %psr, %l0 + mov %wim, %l3 + + srl %l3, %l0, %l4 ! wim >> cwp + cmp %l4, 1 + bne window_fine ! Branch if not in the invalid window + nop + +! Handle window overflow + + mov %g1, %l4 ! Save g1, we use it to hold the wim + srl %l3, 1, %g1 ! Rotate wim right + tst %g1 + bg good_wim ! Branch if new wim is non-zero + nop + +! At this point, we need to bring a 1 into the high order bit of the wim. +! Since we don't want to make any assumptions about the number of register +! windows, we figure it out dynamically so as to setup the wim correctly. + + not %g1 ! Fill g1 with ones + mov %g1, %wim ! Fill the wim with ones + nop + nop + nop + mov %wim, %g1 ! Read back the wim + inc %g1 ! Now g1 has 1 just to left of wim + srl %g1, 1, %g1 ! Now put 1 at top of wim + mov %g0, %wim ! Clear wim so that subsequent save + nop ! won't trap + nop + nop + +good_wim: + save %g0, %g0, %g0 ! Slip into next window + mov %g1, %wim ! Install the new wim + + std %l0, [%sp + 0 * 4] ! save L & I registers + std %l2, [%sp + 2 * 4] + std %l4, [%sp + 4 * 4] + std %l6, [%sp + 6 * 4] + + std %i0, [%sp + 8 * 4] + std %i2, [%sp + 10 * 4] + std %i4, [%sp + 12 * 4] + std %i6, [%sp + 14 * 4] + + restore ! Go back to trap window. + mov %l4, %g1 ! Restore %g1 + +window_fine: + sethi %hi(in_trap_handler), %l4 + ld [%lo(in_trap_handler) + %l4], %l5 + tst %l5 + bg recursive_trap + inc %l5 + + set trapstack+1000*4, %sp ! Switch to trap stack + +recursive_trap: + st %l5, [%lo(in_trap_handler) + %l4] + sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals + ! + hidden arg + arg spill + ! + doubleword alignment + ! + registers[72] local var + + std %g0, [%sp + (24 + 0) * 4] ! registers[Gx] + std %g2, [%sp + (24 + 2) * 4] + std %g4, [%sp + (24 + 4) * 4] + std %g6, [%sp + (24 + 6) * 4] + + std %i0, [%sp + (24 + 8) * 4] ! registers[Ox] + std %i2, [%sp + (24 + 10) * 4] + std %i4, [%sp + (24 + 12) * 4] + std %i6, [%sp + (24 + 14) * 4] + ! F0->F31 not implemented + mov %y, %l4 + mov %tbr, %l5 + st %l4, [%sp + (24 + 64) * 4] ! Y + st %l0, [%sp + (24 + 65) * 4] ! PSR + st %l3, [%sp + (24 + 66) * 4] ! WIM + st %l5, [%sp + (24 + 67) * 4] ! TBR + st %l1, [%sp + (24 + 68) * 4] ! PC + st %l2, [%sp + (24 + 69) * 4] ! NPC + + ! CPSR and FPSR not impl + + or %l0, 0xf20, %l4 + mov %l4, %psr ! Turn on traps, disable interrupts + + call _handle_exception + add %sp, 24 * 4, %o0 ! Pass address of registers + +! Reload all of the registers that aren't on the stack + + ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx] + ldd [%sp + (24 + 2) * 4], %g2 + ldd [%sp + (24 + 4) * 4], %g4 + ldd [%sp + (24 + 6) * 4], %g6 + + ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox] + ldd [%sp + (24 + 10) * 4], %i2 + ldd [%sp + (24 + 12) * 4], %i4 + ldd [%sp + (24 + 14) * 4], %i6 + + ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR + ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC + + restore ! Ensure that previous window is valid + save %g0, %g0, %g0 ! by causing a window_underflow trap + + mov %l0, %y + mov %l1, %psr ! Make sure that traps are disabled + ! for rett + + sethi %hi(in_trap_handler), %l4 + ld [%lo(in_trap_handler) + %l4], %l5 + dec %l5 + st %l5, [%lo(in_trap_handler) + %l4] + + jmpl %l2, %g0 ! Restore old PC + rett %l3 ! Restore old nPC +"); + +/* Convert ch from a hex digit to an int */ + +static int +hex (unsigned char ch) +{ + if (ch >= 'a' && ch <= 'f') + return ch-'a'+10; + if (ch >= '0' && ch <= '9') + return ch-'0'; + if (ch >= 'A' && ch <= 'F') + return ch-'A'+10; + return -1; +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +/* scan for the sequence $# */ + +unsigned char * +getpacket (void) +{ + unsigned char *buffer = &remcomInBuffer[0]; + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + while (1) + { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar ()) != '$') + ; + +retry: + checksum = 0; + xmitcsum = -1; + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX - 1) + { + ch = getDebugChar (); + if (ch == '$') + goto retry; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + ch = getDebugChar (); + xmitcsum = hex (ch) << 4; + ch = getDebugChar (); + xmitcsum += hex (ch); + + if (checksum != xmitcsum) + { + putDebugChar ('-'); /* failed checksum */ + } + else + { + putDebugChar ('+'); /* successful transfer */ + + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + return &buffer[3]; + } + + return &buffer[0]; + } + } + } +} + +/* send the packet in buffer. */ + +static void +putpacket (unsigned char *buffer) +{ + unsigned char checksum; + int count; + unsigned char ch; + + /* $#. */ + do + { + putDebugChar('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum & 0xf]); + + } + while (getDebugChar() != '+'); +} + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; + +/* Convert the memory pointed to by mem into hex, placing result in buf. + * Return a pointer to the last char put in buf (null), in case of mem fault, + * return 0. + * If MAY_FAULT is non-zero, then we will handle memory faults by returning + * a 0, else treat a fault like any other fault in the stub. + */ + +static unsigned char * +mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault) +{ + unsigned char ch; + + set_mem_fault_trap(may_fault); + + while (count-- > 0) + { + ch = *mem++; + if (mem_err) + return 0; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } + + *buf = 0; + + set_mem_fault_trap(0); + + return buf; +} + +/* convert the hex array pointed to by buf into binary to be placed in mem + * return a pointer to the character AFTER the last byte written */ + +static char * +hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + set_mem_fault_trap(may_fault); + + for (i=0; itt && ht->signo; ht++) + exceptionHandler(ht->tt, trap_low); + + initialized = 1; +} + +asm (" +! Trap handler for memory errors. This just sets mem_err to be non-zero. It +! assumes that %l1 is non-zero. This should be safe, as it is doubtful that +! 0 would ever contain code that could mem fault. This routine will skip +! past the faulting instruction after setting mem_err. + + .text + .align 4 + +_fltr_set_mem_err: + sethi %hi(_mem_err), %l0 + st %l1, [%l0 + %lo(_mem_err)] + jmpl %l2, %g0 + rett %l2+4 +"); + +static void +set_mem_fault_trap (int enable) +{ + extern void fltr_set_mem_err(); + mem_err = 0; + + if (enable) + exceptionHandler(9, fltr_set_mem_err); + else + exceptionHandler(9, trap_low); +} + +/* Convert the SPARC hardware trap type code to a unix signal number. */ + +static int +computeSignal (int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +/* + * While we find nice hex chars, build an int. + * Return number of chars processed. + */ + +static int +hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex(**ptr); + if (hexValue < 0) + break; + + *intValue = (*intValue << 4) | hexValue; + numChars ++; + + (*ptr)++; + } + + return (numChars); +} + +/* + * This function does all command procesing for interfacing to gdb. It + * returns 1 if you should skip the instruction at the trap address, 0 + * otherwise. + */ + +extern void breakinst(); + +static void +handle_exception (unsigned long *registers) +{ + int tt; /* Trap type */ + int sigval; + int addr; + int length; + char *ptr; + unsigned long *sp; + +/* First, we must force all of the windows to be spilled out */ + + asm(" save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + restore + restore + restore + restore + restore + restore + restore + restore +"); + + if (registers[PC] == (unsigned long)breakinst) + { + registers[PC] = registers[NPC]; + registers[NPC] += 4; + } + + sp = (unsigned long *)registers[SP]; + + tt = (registers[TBR] >> 4) & 0xff; + + /* reply to host that an exception has occurred */ + sigval = computeSignal(tt); + ptr = remcomOutBuffer; + + *ptr++ = 'T'; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[PC >> 4]; + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[FP >> 4]; + *ptr++ = hexchars[FP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */ + *ptr++ = ';'; + + *ptr++ = hexchars[SP >> 4]; + *ptr++ = hexchars[SP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)&sp, ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[NPC >> 4]; + *ptr++ = hexchars[NPC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[NPC], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[O7 >> 4]; + *ptr++ = hexchars[O7 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[O7], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = 0; + + putpacket(remcomOutBuffer); + + while (1) + { + remcomOutBuffer[0] = 0; + + ptr = getpacket(); + switch (*ptr++) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval & 0xf]; + remcomOutBuffer[3] = 0; + break; + + case 'd': /* toggle debug flag */ + break; + + case 'g': /* return the value of the CPU registers */ + { + ptr = remcomOutBuffer; + ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */ + ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */ + memset(ptr, '0', 32 * 8); /* Floating point */ + mem2hex((char *)®isters[Y], + ptr + 32 * 4 * 2, + 8 * 4, + 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + } + break; + + case 'G': /* set the value of the CPU registers - return OK */ + { + unsigned long *newsp, psr; + + psr = registers[PSR]; + + hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */ + hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */ + hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y], + 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + + /* See if the stack pointer has moved. If so, then copy the saved + locals and ins to the new location. This keeps the window + overflow and underflow routines happy. */ + + newsp = (unsigned long *)registers[SP]; + if (sp != newsp) + sp = memcpy(newsp, sp, 16 * 4); + + /* Don't allow CWP to be modified. */ + + if (psr != registers[PSR]) + registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f); + + strcpy(remcomOutBuffer,"OK"); + } + break; + + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* Try to read %x,%x. */ + + if (hexToInt(&ptr, &addr) + && *ptr++ == ',' + && hexToInt(&ptr, &length)) + { + if (mem2hex((char *)addr, remcomOutBuffer, length, 1)) + break; + + strcpy (remcomOutBuffer, "E03"); + } + else + strcpy(remcomOutBuffer,"E01"); + break; + + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* Try to read '%x,%x:'. */ + + if (hexToInt(&ptr, &addr) + && *ptr++ == ',' + && hexToInt(&ptr, &length) + && *ptr++ == ':') + { + if (hex2mem(ptr, (char *)addr, length, 1)) + strcpy(remcomOutBuffer, "OK"); + else + strcpy(remcomOutBuffer, "E03"); + } + else + strcpy(remcomOutBuffer, "E02"); + break; + + case 'c': /* cAA..AA Continue at address AA..AA(optional) */ + /* try to read optional parameter, pc unchanged if no parm */ + + if (hexToInt(&ptr, &addr)) + { + registers[PC] = addr; + registers[NPC] = addr + 4; + } + +/* Need to flush the instruction cache here, as we may have deposited a + breakpoint, and the icache probably has no way of knowing that a data ref to + some location may have changed something that is in the instruction cache. + */ + + flush_i_cache(); + return; + + /* kill the program */ + case 'k' : /* do nothing */ + break; +#if 0 + case 't': /* Test feature */ + asm (" std %f30,[%sp]"); + break; +#endif + case 'r': /* Reset */ + asm ("call 0 + nop "); + break; + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint (void) +{ + if (!initialized) + return; + + asm(" .globl _breakinst + + _breakinst: ta 1 + "); +} diff --git a/contrib/gdb-7/gdb/symfile.c b/contrib/gdb-7/gdb/symfile.c index 45cd175b53..5ed25913cb 100644 --- a/contrib/gdb-7/gdb/symfile.c +++ b/contrib/gdb-7/gdb/symfile.c @@ -1,6 +1,6 @@ /* Generic symbol file reading for the GNU debugger, GDB. - Copyright (C) 1990-2012 Free Software Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. Contributed by Cygnus Support, using pieces from other GDB modules. @@ -55,6 +55,8 @@ #include "solib.h" #include "remote.h" #include "stack.h" +#include "gdb_bfd.h" +#include "cli/cli-utils.h" #include #include @@ -81,10 +83,6 @@ static void clear_symtab_users_cleanup (void *ignore); /* Global variables owned by this file. */ int readnow_symbol_files; /* Read full symbols immediately. */ -/* External variables and functions referenced. */ - -extern void report_transfer_performance (unsigned long, time_t, time_t); - /* Functions this file defines. */ static void load_command (char *, int); @@ -103,12 +101,6 @@ static void decrement_reading_symtab (void *); static void overlay_invalidate_all (void); -void list_overlays_command (char *, int); - -void map_overlay_command (char *, int); - -void unmap_overlay_command (char *, int); - static void overlay_auto_command (char *, int); static void overlay_manual_command (char *, int); @@ -147,23 +139,6 @@ DEF_VEC_P (sym_fns_ptr); static VEC (sym_fns_ptr) *symtab_fns = NULL; -/* Flag for whether user will be reloading symbols multiple times. - Defaults to ON for VxWorks, otherwise OFF. */ - -#ifdef SYMBOL_RELOADING_DEFAULT -int symbol_reloading = SYMBOL_RELOADING_DEFAULT; -#else -int symbol_reloading = 0; -#endif -static void -show_symbol_reloading (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) -{ - fprintf_filtered (file, _("Dynamic symbol table reloading " - "multiple times in one run is %s.\n"), - value); -} - /* If non-zero, shared library symbols will be added automatically when the inferior is created, new libraries are loaded, or when attaching to the inferior. This is almost always what users will @@ -177,56 +152,6 @@ show_symbol_reloading (struct ui_file *file, int from_tty, int auto_solib_add = 1; -/* Make a null terminated copy of the string at PTR with SIZE characters in - the obstack pointed to by OBSTACKP . Returns the address of the copy. - Note that the string at PTR does not have to be null terminated, I.e. it - may be part of a larger string and we are only saving a substring. */ - -char * -obsavestring (const char *ptr, int size, struct obstack *obstackp) -{ - char *p = (char *) obstack_alloc (obstackp, size + 1); - /* Open-coded memcpy--saves function call time. These strings are usually - short. FIXME: Is this really still true with a compiler that can - inline memcpy? */ - { - const char *p1 = ptr; - char *p2 = p; - const char *end = ptr + size; - - while (p1 != end) - *p2++ = *p1++; - } - p[size] = 0; - return p; -} - -/* Concatenate NULL terminated variable argument list of `const char *' - strings; return the new string. Space is found in the OBSTACKP. - Argument list must be terminated by a sentinel expression `(char *) - NULL'. */ - -char * -obconcat (struct obstack *obstackp, ...) -{ - va_list ap; - - va_start (ap, obstackp); - for (;;) - { - const char *s = va_arg (ap, const char *); - - if (s == NULL) - break; - - obstack_grow_str (obstackp, s); - } - va_end (ap); - obstack_1grow (obstackp, 0); - - return obstack_finish (obstackp); -} - /* True if we are reading a symbol table. */ int currently_reading_symtab = 0; @@ -561,7 +486,7 @@ addrs_section_compar (const void *ap, const void *bp) { const struct other_sections *a = *((struct other_sections **) ap); const struct other_sections *b = *((struct other_sections **) bp); - int retval, a_idx, b_idx; + int retval; retval = strcmp (addr_section_name (a->name), addr_section_name (b->name)); if (retval) @@ -892,9 +817,85 @@ default_symfile_segments (bfd *abfd) return data; } +/* This is a convenience function to call sym_read for OBJFILE and + possibly force the partial symbols to be read. */ + +static void +read_symbols (struct objfile *objfile, int add_flags) +{ + (*objfile->sf->sym_read) (objfile, add_flags); + + /* find_separate_debug_file_in_section should be called only if there is + single binary with no existing separate debug info file. */ + if (!objfile_has_partial_symbols (objfile) + && objfile->separate_debug_objfile == NULL + && objfile->separate_debug_objfile_backlink == NULL) + { + bfd *abfd = find_separate_debug_file_in_section (objfile); + struct cleanup *cleanup = make_cleanup_bfd_unref (abfd); + + if (abfd != NULL) + symbol_file_add_separate (abfd, add_flags, objfile); + + do_cleanups (cleanup); + } + if ((add_flags & SYMFILE_NO_READ) == 0) + require_partial_symbols (objfile, 0); +} + +/* Initialize entry point information for this objfile. */ + +static void +init_entry_point_info (struct objfile *objfile) +{ + /* Save startup file's range of PC addresses to help blockframe.c + decide where the bottom of the stack is. */ + + if (bfd_get_file_flags (objfile->obfd) & EXEC_P) + { + /* Executable file -- record its entry point so we'll recognize + the startup file because it contains the entry point. */ + objfile->ei.entry_point = bfd_get_start_address (objfile->obfd); + objfile->ei.entry_point_p = 1; + } + else if (bfd_get_file_flags (objfile->obfd) & DYNAMIC + && bfd_get_start_address (objfile->obfd) != 0) + { + /* Some shared libraries may have entry points set and be + runnable. There's no clear way to indicate this, so just check + for values other than zero. */ + objfile->ei.entry_point = bfd_get_start_address (objfile->obfd); + objfile->ei.entry_point_p = 1; + } + else + { + /* Examination of non-executable.o files. Short-circuit this stuff. */ + objfile->ei.entry_point_p = 0; + } + + if (objfile->ei.entry_point_p) + { + CORE_ADDR entry_point = objfile->ei.entry_point; + + /* Make certain that the address points at real code, and not a + function descriptor. */ + entry_point + = gdbarch_convert_from_func_ptr_addr (objfile->gdbarch, + entry_point, + ¤t_target); + + /* Remove any ISA markers, so that this matches entries in the + symbol table. */ + objfile->ei.entry_point + = gdbarch_addr_bits_remove (objfile->gdbarch, entry_point); + } +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. + This function does not set the OBJFILE's entry-point info. + OBJFILE is where the symbols are to be read from. ADDRS is the list of section load addresses. If the user has given @@ -922,12 +923,12 @@ default_symfile_segments (bfd *abfd) an extra symbol file such as dynamically loaded code, and wether breakpoint reset should be deferred. */ -void -syms_from_objfile (struct objfile *objfile, - struct section_addr_info *addrs, - struct section_offsets *offsets, - int num_offsets, - int add_flags) +static void +syms_from_objfile_1 (struct objfile *objfile, + struct section_addr_info *addrs, + struct section_offsets *offsets, + int num_offsets, + int add_flags) { struct section_addr_info *local_addr = NULL; struct cleanup *old_chain; @@ -935,11 +936,21 @@ syms_from_objfile (struct objfile *objfile, gdb_assert (! (addrs && offsets)); - init_entry_point_info (objfile); objfile->sf = find_sym_fns (objfile->obfd); if (objfile->sf == NULL) - return; /* No symbols. */ + { + /* No symbols to load, but we still need to make sure + that the section_offsets table is allocated. */ + int num_sections = bfd_count_sections (objfile->obfd); + size_t size = SIZEOF_N_SECTION_OFFSETS (num_offsets); + + objfile->num_sections = num_sections; + objfile->section_offsets + = obstack_alloc (&objfile->objfile_obstack, size); + memset (objfile->section_offsets, 0, size); + return; + } /* Make sure that partially constructed symbol tables will be cleaned up if an error occurs during symbol reading. */ @@ -1012,10 +1023,7 @@ syms_from_objfile (struct objfile *objfile, init_objfile_sect_indices (objfile); } - (*objfile->sf->sym_read) (objfile, add_flags); - - if ((add_flags & SYMFILE_NO_READ) == 0) - require_partial_symbols (objfile, 0); + read_symbols (objfile, add_flags); /* Discard cleanups as symbol reading was successful. */ @@ -1023,6 +1031,20 @@ syms_from_objfile (struct objfile *objfile, xfree (local_addr); } +/* Same as syms_from_objfile_1, but also initializes the objfile + entry-point info. */ + +void +syms_from_objfile (struct objfile *objfile, + struct section_addr_info *addrs, + struct section_offsets *offsets, + int num_offsets, + int add_flags) +{ + syms_from_objfile_1 (objfile, addrs, offsets, num_offsets, add_flags); + init_entry_point_info (objfile); +} + /* Perform required actions after either reading in the initial symbols for a new objfile, or mapping in the symbols from a reusable objfile. ADD_FLAGS is a bitmask of enum symfile_add_flags. */ @@ -1053,7 +1075,7 @@ new_symfile_objfile (struct objfile *objfile, int add_flags) loaded file. ABFD is a BFD already open on the file, as from symfile_bfd_open. - This BFD will be closed on error, and is always consumed by this function. + A new reference is acquired by this function. ADD_FLAGS encodes verbosity, whether this is main symbol file or extra, such as dynamically loaded code, and what to do with breakpoins. @@ -1077,7 +1099,6 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int flags, struct objfile *parent) { struct objfile *objfile; - struct cleanup *my_cleanups; const char *name = bfd_get_filename (abfd); const int from_tty = add_flags & SYMFILE_VERBOSE; const int mainline = add_flags & SYMFILE_MAINLINE; @@ -1091,8 +1112,6 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, add_flags &= ~SYMFILE_NO_READ; } - my_cleanups = make_cleanup_bfd_close (abfd); - /* Give user a chance to burp if we'd be interactively wiping out any existing symbols. */ @@ -1103,7 +1122,6 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, error (_("Not confirmed.")); objfile = allocate_objfile (abfd, flags | (mainline ? OBJF_MAINLINE : 0)); - discard_cleanups (my_cleanups); if (parent) add_separate_debug_objfile (objfile, parent); @@ -1224,8 +1242,13 @@ struct objfile * symbol_file_add (char *name, int add_flags, struct section_addr_info *addrs, int flags) { - return symbol_file_add_from_bfd (symfile_bfd_open (name), add_flags, addrs, - flags, NULL); + bfd *bfd = symfile_bfd_open (name); + struct cleanup *cleanup = make_cleanup_bfd_unref (bfd); + struct objfile *objf; + + objf = symbol_file_add_from_bfd (bfd, add_flags, addrs, flags, NULL); + do_cleanups (cleanup); + return objf; } @@ -1246,14 +1269,17 @@ symbol_file_add_main (char *args, int from_tty) static void symbol_file_add_main_1 (char *args, int from_tty, int flags) { - const int add_flags = SYMFILE_MAINLINE | (from_tty ? SYMFILE_VERBOSE : 0); + const int add_flags = (current_inferior ()->symfile_flags + | SYMFILE_MAINLINE | (from_tty ? SYMFILE_VERBOSE : 0)); + symbol_file_add (args, add_flags, NULL, flags); /* Getting new symbols may change our opinion about what is frameless. */ reinit_frame_cache (); - set_initial_language (); + if ((flags & SYMFILE_NO_READ) == 0) + set_initial_language (); } void @@ -1338,7 +1364,7 @@ get_file_crc (bfd *abfd, unsigned long *file_crc_return) } if (count == 0) break; - file_crc = gnu_debuglink_crc32 (file_crc, buffer, count); + file_crc = bfd_calc_gnu_debuglink_crc32 (file_crc, buffer, count); } *file_crc_return = file_crc; @@ -1364,7 +1390,7 @@ separate_debug_file_exists (const char *name, unsigned long crc, if (filename_cmp (name, parent_objfile->name) == 0) return 0; - abfd = bfd_open_maybe_remote (name); + abfd = gdb_bfd_open_maybe_remote (name); if (!abfd) return 0; @@ -1386,7 +1412,7 @@ separate_debug_file_exists (const char *name, unsigned long crc, if (abfd_stat.st_dev == parent_stat.st_dev && abfd_stat.st_ino == parent_stat.st_ino) { - bfd_close (abfd); + gdb_bfd_unref (abfd); return 0; } verified_as_different = 1; @@ -1396,7 +1422,7 @@ separate_debug_file_exists (const char *name, unsigned long crc, file_crc_p = get_file_crc (abfd, &file_crc); - bfd_close (abfd); + gdb_bfd_unref (abfd); if (!file_crc_p) return 0; @@ -1441,118 +1467,174 @@ show_debug_file_directory (struct ui_file *file, int from_tty, #define DEBUG_SUBDIRECTORY ".debug" #endif -char * -find_separate_debug_file_by_debuglink (struct objfile *objfile) +/* Find a separate debuginfo file for OBJFILE, using DIR as the directory + where the original file resides (may not be the same as + dirname(objfile->name) due to symlinks), and DEBUGLINK as the file we are + looking for. Returns the name of the debuginfo, of NULL. */ + +static char * +find_separate_debug_file (const char *dir, + const char *canon_dir, + const char *debuglink, + unsigned long crc32, struct objfile *objfile) { - char *basename, *debugdir; - char *dir = NULL; - char *debugfile = NULL; - char *canon_name = NULL; - unsigned long crc32; + char *debugdir; + char *debugfile; int i; + VEC (char_ptr) *debugdir_vec; + struct cleanup *back_to; + int ix; - 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. */ - goto cleanup_return_debugfile; - - dir = xstrdup (objfile->name); - - /* Strip off the final filename part, leaving the directory name, - followed by a slash. The directory can be relative or absolute. */ - for (i = strlen(dir) - 1; i >= 0; i--) - { - if (IS_DIR_SEPARATOR (dir[i])) - break; - } - /* If I is -1 then no directory is present there and DIR will be "". */ - dir[i+1] = '\0'; - - /* Set I to max (strlen (canon_name), strlen (dir)). */ - canon_name = lrealpath (dir); + /* Set I to max (strlen (canon_dir), strlen (dir)). */ i = strlen (dir); - if (canon_name && strlen (canon_name) > i) - i = strlen (canon_name); + if (canon_dir != NULL && strlen (canon_dir) > i) + i = strlen (canon_dir); debugfile = xmalloc (strlen (debug_file_directory) + 1 + i + strlen (DEBUG_SUBDIRECTORY) + strlen ("/") - + strlen (basename) + + strlen (debuglink) + 1); /* First try in the same directory as the original file. */ strcpy (debugfile, dir); - strcat (debugfile, basename); + strcat (debugfile, debuglink); if (separate_debug_file_exists (debugfile, crc32, objfile)) - goto cleanup_return_debugfile; + return debugfile; /* Then try in the subdirectory named DEBUG_SUBDIRECTORY. */ strcpy (debugfile, dir); strcat (debugfile, DEBUG_SUBDIRECTORY); strcat (debugfile, "/"); - strcat (debugfile, basename); + strcat (debugfile, debuglink); if (separate_debug_file_exists (debugfile, crc32, objfile)) - goto cleanup_return_debugfile; + return debugfile; /* Then try in the global debugfile directories. - + Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will cause "/..." lookups. */ - debugdir = debug_file_directory; - do - { - char *debugdir_end; - - while (*debugdir == DIRNAME_SEPARATOR) - debugdir++; + debugdir_vec = dirnames_to_char_ptr_vec (debug_file_directory); + back_to = make_cleanup_free_char_ptr_vec (debugdir_vec); - debugdir_end = strchr (debugdir, DIRNAME_SEPARATOR); - if (debugdir_end == NULL) - debugdir_end = &debugdir[strlen (debugdir)]; - - memcpy (debugfile, debugdir, debugdir_end - debugdir); - debugfile[debugdir_end - debugdir] = 0; + for (ix = 0; VEC_iterate (char_ptr, debugdir_vec, ix, debugdir); ++ix) + { + strcpy (debugfile, debugdir); strcat (debugfile, "/"); strcat (debugfile, dir); - strcat (debugfile, basename); + strcat (debugfile, debuglink); if (separate_debug_file_exists (debugfile, crc32, objfile)) - goto cleanup_return_debugfile; + return debugfile; /* If the file is in the sysroot, try using its base path in the global debugfile directory. */ - if (canon_name - && filename_ncmp (canon_name, gdb_sysroot, + if (canon_dir != NULL + && filename_ncmp (canon_dir, gdb_sysroot, strlen (gdb_sysroot)) == 0 - && IS_DIR_SEPARATOR (canon_name[strlen (gdb_sysroot)])) + && IS_DIR_SEPARATOR (canon_dir[strlen (gdb_sysroot)])) { - memcpy (debugfile, debugdir, debugdir_end - debugdir); - debugfile[debugdir_end - debugdir] = 0; - strcat (debugfile, canon_name + strlen (gdb_sysroot)); + strcpy (debugfile, debugdir); + strcat (debugfile, canon_dir + strlen (gdb_sysroot)); strcat (debugfile, "/"); - strcat (debugfile, basename); + strcat (debugfile, debuglink); if (separate_debug_file_exists (debugfile, crc32, objfile)) - goto cleanup_return_debugfile; + return debugfile; } - - debugdir = debugdir_end; } - while (*debugdir != 0); - + + do_cleanups (back_to); xfree (debugfile); - debugfile = NULL; + return NULL; +} + +/* Modify PATH to contain only "directory/" part of PATH. + If there were no directory separators in PATH, PATH will be empty + string on return. */ + +static void +terminate_after_last_dir_separator (char *path) +{ + int i; + + /* Strip off the final filename part, leaving the directory name, + followed by a slash. The directory can be relative or absolute. */ + for (i = strlen(path) - 1; i >= 0; i--) + if (IS_DIR_SEPARATOR (path[i])) + break; + + /* If I is -1 then no directory is present there and DIR will be "". */ + path[i + 1] = '\0'; +} + +/* Find separate debuginfo for OBJFILE (using .gnu_debuglink section). + Returns pathname, or NULL. */ -cleanup_return_debugfile: - xfree (canon_name); - xfree (basename); - xfree (dir); +char * +find_separate_debug_file_by_debuglink (struct objfile *objfile) +{ + char *debuglink; + char *dir, *canon_dir; + char *debugfile; + unsigned long crc32; + struct cleanup *cleanups; + + debuglink = get_debug_link_info (objfile, &crc32); + + if (debuglink == NULL) + { + /* There's no separate debug info, hence there's no way we could + load it => no warning. */ + return NULL; + } + + cleanups = make_cleanup (xfree, debuglink); + dir = xstrdup (objfile->name); + make_cleanup (xfree, dir); + terminate_after_last_dir_separator (dir); + canon_dir = lrealpath (dir); + + debugfile = find_separate_debug_file (dir, canon_dir, debuglink, + crc32, objfile); + xfree (canon_dir); + + if (debugfile == NULL) + { +#ifdef HAVE_LSTAT + /* For PR gdb/9538, try again with realpath (if different from the + original). */ + + struct stat st_buf; + + if (lstat (objfile->name, &st_buf) == 0 && S_ISLNK(st_buf.st_mode)) + { + char *symlink_dir; + + symlink_dir = lrealpath (objfile->name); + if (symlink_dir != NULL) + { + make_cleanup (xfree, symlink_dir); + terminate_after_last_dir_separator (symlink_dir); + if (strcmp (dir, symlink_dir) != 0) + { + /* Different directory, so try using it. */ + debugfile = find_separate_debug_file (symlink_dir, + symlink_dir, + debuglink, + crc32, + objfile); + } + } + } +#endif /* HAVE_LSTAT */ + } + + do_cleanups (cleanups); return debugfile; } @@ -1631,7 +1713,7 @@ set_initial_language (void) else { const char *filename; - + filename = find_main_filename (); if (filename != NULL) lang = deduce_language_from_filename (filename); @@ -1648,15 +1730,20 @@ set_initial_language (void) } /* If NAME is a remote name open the file using remote protocol, otherwise - open it normally. */ + open it normally. Returns a new reference to the BFD. On error, + returns NULL with the BFD error set. */ bfd * -bfd_open_maybe_remote (const char *name) +gdb_bfd_open_maybe_remote (const char *name) { + bfd *result; + if (remote_filename_p (name)) - return remote_bfd_open (name, gnutarget); + result = remote_bfd_open (name, gnutarget); else - return bfd_openr (name, gnutarget); + result = gdb_bfd_open (name, gnutarget, -1); + + return result; } @@ -1674,19 +1761,14 @@ symfile_bfd_open (char *name) if (remote_filename_p (name)) { - name = xstrdup (name); sym_bfd = remote_bfd_open (name, gnutarget); if (!sym_bfd) - { - make_cleanup (xfree, name); - error (_("`%s': can't open to read symbols: %s."), name, - bfd_errmsg (bfd_get_error ())); - } + error (_("`%s': can't open to read symbols: %s."), name, + bfd_errmsg (bfd_get_error ())); if (!bfd_check_format (sym_bfd, bfd_object)) { - bfd_close (sym_bfd); - make_cleanup (xfree, name); + make_cleanup_bfd_unref (sym_bfd); error (_("`%s': can't read symbols: %s."), name, bfd_errmsg (bfd_get_error ())); } @@ -1715,15 +1797,13 @@ symfile_bfd_open (char *name) perror_with_name (name); } - /* Free 1st new malloc'd copy, but keep the 2nd malloc'd copy in - bfd. It'll be freed in free_objfile(). */ xfree (name); name = absolute_name; + make_cleanup (xfree, name); - sym_bfd = bfd_fopen (name, gnutarget, FOPEN_RB, desc); + sym_bfd = gdb_bfd_open (name, gnutarget, desc); if (!sym_bfd) { - close (desc); make_cleanup (xfree, name); error (_("`%s': can't open to read symbols: %s."), name, bfd_errmsg (bfd_get_error ())); @@ -1732,18 +1812,11 @@ symfile_bfd_open (char *name) if (!bfd_check_format (sym_bfd, bfd_object)) { - /* FIXME: should be checking for errors from bfd_close (for one - thing, on error it does not free all the storage associated - with the bfd). */ - bfd_close (sym_bfd); /* This also closes desc. */ - make_cleanup (xfree, name); + make_cleanup_bfd_unref (sym_bfd); error (_("`%s': can't read symbols: %s."), name, bfd_errmsg (bfd_get_error ())); } - /* bfd_usrdata exists for applications and libbfd must not touch it. */ - gdb_assert (bfd_usrdata (sym_bfd) == NULL); - return sym_bfd; } @@ -1876,7 +1949,7 @@ add_section_size_callback (bfd *abfd, asection *asec, void *data) /* Opaque data for load_section_callback. */ struct load_section_data { - unsigned long load_offset; + CORE_ADDR load_offset; struct load_progress_data *progress_data; VEC(memory_write_request_s) *requests; }; @@ -1922,7 +1995,7 @@ load_progress (ULONGEST bytes, void *untyped_arg) this section. */ ui_out_message (current_uiout, 0, "Loading section %s, size %s lma %s\n", args->section_name, hex_string (args->section_size), - paddress (target_gdbarch, args->lma)); + paddress (target_gdbarch (), args->lma)); return; } @@ -1940,10 +2013,10 @@ load_progress (ULONGEST bytes, void *untyped_arg) if (target_read_memory (args->lma, check, bytes) != 0) error (_("Download verify read failed at %s"), - paddress (target_gdbarch, args->lma)); + paddress (target_gdbarch (), args->lma)); if (memcmp (args->buffer, check, bytes) != 0) error (_("Download verify compare failed at %s"), - paddress (target_gdbarch, args->lma)); + paddress (target_gdbarch (), args->lma)); do_cleanups (verify_cleanups); } totals->data_count += bytes; @@ -1951,7 +2024,7 @@ load_progress (ULONGEST bytes, void *untyped_arg) args->buffer += bytes; totals->write_count += 1; args->section_sent += bytes; - if (quit_flag + if (check_quit_flag () || (deprecated_ui_load_progress_hook != NULL && deprecated_ui_load_progress_hook (args->section_name, args->section_sent))) @@ -2054,9 +2127,9 @@ generic_load (char *args, int from_tty) if (argv[1] != NULL) { - char *endptr; + const char *endptr; - cbdata.load_offset = strtoul (argv[1], &endptr, 0); + cbdata.load_offset = strtoulst (argv[1], &endptr, 0); /* If the last word was not a valid number then treat it as a file name with spaces in. */ @@ -2068,17 +2141,14 @@ generic_load (char *args, int from_tty) } /* Open the file for loading. */ - loadfile_bfd = bfd_openr (filename, gnutarget); + loadfile_bfd = gdb_bfd_open (filename, gnutarget, -1); if (loadfile_bfd == NULL) { perror_with_name (filename); return; } - /* FIXME: should be checking for errors from bfd_close (for one thing, - on error it does not free all the storage associated with the - bfd). */ - make_cleanup_bfd_close (loadfile_bfd); + make_cleanup_bfd_unref (loadfile_bfd); if (!bfd_check_format (loadfile_bfd, bfd_object)) { @@ -2100,8 +2170,9 @@ generic_load (char *args, int from_tty) gettimeofday (&end_time, NULL); entry = bfd_get_start_address (loadfile_bfd); + entry = gdbarch_addr_bits_remove (target_gdbarch (), entry); ui_out_text (uiout, "Start address "); - ui_out_field_fmt (uiout, "address", "%s", paddress (target_gdbarch, entry)); + ui_out_field_fmt (uiout, "address", "%s", paddress (target_gdbarch (), entry)); ui_out_text (uiout, ", load size "); ui_out_field_fmt (uiout, "load-size", "%lu", total_progress.data_count); ui_out_text (uiout, "\n"); @@ -2134,24 +2205,6 @@ generic_load (char *args, int from_tty) /* Report how fast the transfer went. */ -/* DEPRECATED: cagney/1999-10-18: report_transfer_performance is being - replaced by print_transfer_performance (with a very different - function signature). */ - -void -report_transfer_performance (unsigned long data_count, time_t start_time, - time_t end_time) -{ - struct timeval start, end; - - start.tv_sec = start_time; - start.tv_usec = 0; - end.tv_sec = end_time; - end.tv_usec = 0; - - print_transfer_performance (gdb_stdout, data_count, 0, &start, &end); -} - void print_transfer_performance (struct ui_file *stream, unsigned long data_count, @@ -2369,15 +2422,22 @@ add_symbol_file_command (char *args, int from_tty) } +typedef struct objfile *objfilep; + +DEF_VEC_P (objfilep); + /* Re-read symbols if a symbol-file has changed. */ void reread_symbols (void) { struct objfile *objfile; long new_modtime; - int reread_one = 0; struct stat new_statbuf; int res; + VEC (objfilep) *new_objfiles = NULL; + struct cleanup *all_cleanups; + + all_cleanups = make_cleanup (VEC_cleanup (objfilep), &new_objfiles); /* With the addition of shared libraries, this should be modified, the load time should be saved in the partial symbol tables, since @@ -2467,18 +2527,26 @@ reread_symbols (void) clear_objfile_data (objfile); - /* Clean up any state BFD has sitting around. We don't need - to close the descriptor but BFD lacks a way of closing the - BFD without closing the descriptor. */ - obfd_filename = bfd_get_filename (objfile->obfd); - if (!bfd_close (objfile->obfd)) - error (_("Can't close BFD for %s: %s"), objfile->name, - bfd_errmsg (bfd_get_error ())); - objfile->obfd = bfd_open_maybe_remote (obfd_filename); - if (objfile->obfd == NULL) - error (_("Can't open %s to read symbols."), objfile->name); - else - objfile->obfd = gdb_bfd_ref (objfile->obfd); + /* Clean up any state BFD has sitting around. */ + { + struct bfd *obfd = objfile->obfd; + + obfd_filename = bfd_get_filename (objfile->obfd); + /* Open the new BFD before freeing the old one, so that + the filename remains live. */ + objfile->obfd = gdb_bfd_open_maybe_remote (obfd_filename); + if (objfile->obfd == NULL) + { + /* We have to make a cleanup and error here, rather + than erroring later, because once we unref OBFD, + OBFD_FILENAME will be freed. */ + make_cleanup_bfd_unref (obfd); + error (_("Can't open %s to read symbols."), obfd_filename); + } + gdb_bfd_unref (obfd); + } + + objfile->name = bfd_get_filename (objfile->obfd); /* bfd_openr sets cacheable to true, which is what we want. */ if (!bfd_check_format (objfile->obfd, bfd_object)) error (_("Can't read symbols from %s: %s."), objfile->name, @@ -2506,10 +2574,6 @@ reread_symbols (void) /* Free the obstacks for non-reusable objfiles. */ psymbol_bcache_free (objfile->psymbol_cache); objfile->psymbol_cache = psymbol_bcache_init (); - bcache_xfree (objfile->macro_cache); - objfile->macro_cache = bcache_xmalloc (NULL, NULL); - bcache_xfree (objfile->filename_cache); - objfile->filename_cache = bcache_xmalloc (NULL,NULL); if (objfile->demangled_names_hash != NULL) { htab_delete (objfile->demangled_names_hash); @@ -2523,23 +2587,19 @@ reread_symbols (void) objfile->free_psymtabs = NULL; objfile->template_symbols = NULL; objfile->msymbols = NULL; - objfile->deprecated_sym_private = NULL; objfile->minimal_symbol_count = 0; memset (&objfile->msymbol_hash, 0, sizeof (objfile->msymbol_hash)); memset (&objfile->msymbol_demangled_hash, 0, sizeof (objfile->msymbol_demangled_hash)); + set_objfile_per_bfd (objfile); + /* obstack_init also initializes the obstack so it is empty. We could use obstack_specify_allocation but - gdb_obstack.h specifies the alloc/dealloc - functions. */ + gdb_obstack.h specifies the alloc/dealloc functions. */ obstack_init (&objfile->objfile_obstack); - if (build_objfile_section_table (objfile)) - { - error (_("Can't find the file sections in `%s': %s"), - objfile->name, bfd_errmsg (bfd_get_error ())); - } + build_objfile_section_table (objfile); terminate_minimal_symbol_table (objfile); /* We use the same section offsets as from last time. I'm not @@ -2561,14 +2621,9 @@ reread_symbols (void) (*objfile->sf->sym_init) (objfile); clear_complaints (&symfile_complaints, 1, 1); - /* Do not set flags as this is safe and we don't want to be - verbose. */ - (*objfile->sf->sym_read) (objfile, 0); - if ((objfile->flags & OBJF_PSYMTABS_READ) != 0) - { - objfile->flags &= ~OBJF_PSYMTABS_READ; - require_partial_symbols (objfile, 0); - } + + objfile->flags &= ~OBJF_PSYMTABS_READ; + read_symbols (objfile, 0); if (!objfile_has_symbols (objfile)) { @@ -2592,21 +2647,33 @@ reread_symbols (void) and now, we *want* this to be out of date, so don't call stat again now. */ objfile->mtime = new_modtime; - reread_one = 1; init_entry_point_info (objfile); + + VEC_safe_push (objfilep, new_objfiles, objfile); } } - if (reread_one) + if (new_objfiles) { + int ix; + /* Notify objfiles that we've modified objfile sections. */ objfiles_changed (); clear_symtab_users (0); + + /* clear_objfile_data for each objfile was called before freeing it and + observer_notify_new_objfile (NULL) has been called by + clear_symtab_users above. Notify the new files now. */ + for (ix = 0; VEC_iterate (objfilep, new_objfiles, ix, objfile); ix++) + observer_notify_new_objfile (objfile); + /* At least one objfile has changed, so we can consider that the executable we're debugging has changed too. */ observer_notify_executable_changed (); } + + do_cleanups (all_cleanups); } @@ -2672,8 +2739,7 @@ set_ext_lang_command (char *args, int from_tty, struct cmd_list_element *e) *cp++ = '\0'; /* Find beginning of second arg, which should be a source language. */ - while (*cp && isspace (*cp)) - cp++; + cp = skip_spaces (cp); if (*cp == '\0') error (_("'%s': two arguments required -- " @@ -2807,7 +2873,7 @@ allocate_symtab (const char *filename, struct objfile *objfile) obstack_alloc (&objfile->objfile_obstack, sizeof (struct symtab)); memset (symtab, 0, sizeof (*symtab)); symtab->filename = (char *) bcache (filename, strlen (filename) + 1, - objfile->filename_cache); + objfile->per_bfd->filename_cache); symtab->fullname = NULL; symtab->language = deduce_language_from_filename (filename); symtab->debugformat = "unknown"; @@ -2818,6 +2884,26 @@ allocate_symtab (const char *filename, struct objfile *objfile) symtab->next = objfile->symtabs; objfile->symtabs = symtab; + if (symtab_create_debug) + { + /* Be a bit clever with debugging messages, and don't print objfile + every time, only when it changes. */ + static char *last_objfile_name = NULL; + + if (last_objfile_name == NULL + || strcmp (last_objfile_name, objfile->name) != 0) + { + xfree (last_objfile_name); + last_objfile_name = xstrdup (objfile->name); + fprintf_unfiltered (gdb_stdlog, + "Creating one or more symtabs for objfile %s ...\n", + last_objfile_name); + } + fprintf_unfiltered (gdb_stdlog, + "Created symtab %s for module %s.\n", + host_address_to_string (symtab), filename); + } + return (symtab); } @@ -2923,7 +3009,7 @@ section_is_overlay (struct obj_section *section) { bfd *abfd = section->objfile->obfd; asection *bfd_section = section->the_bfd_section; - + if (bfd_section_lma (abfd, bfd_section) != 0 && bfd_section_lma (abfd, bfd_section) != bfd_section_vma (abfd, bfd_section)) @@ -3159,7 +3245,7 @@ find_pc_mapped_section (CORE_ADDR pc) /* Function: list_overlays_command Print a list of mapped sections and their PC ranges. */ -void +static void list_overlays_command (char *args, int from_tty) { int nmapped = 0; @@ -3199,7 +3285,7 @@ list_overlays_command (char *args, int from_tty) /* Function: map_overlay_command Mark the named section as mapped (ie. residing at its VMA address). */ -void +static void map_overlay_command (char *args, int from_tty) { struct objfile *objfile, *objfile2; @@ -3244,7 +3330,7 @@ map_overlay_command (char *args, int from_tty) Mark the overlay section as unmapped (ie. resident in its LMA address range, rather than the VMA range). */ -void +static void unmap_overlay_command (char *args, int from_tty) { struct objfile *objfile; @@ -3324,7 +3410,7 @@ overlay_load_command (char *args, int from_tty) A place-holder for a mis-typed command. */ /* Command list chain containing all defined "overlay" subcommands. */ -struct cmd_list_element *overlaylist; +static struct cmd_list_element *overlaylist; static void overlay_command (char *args, int from_tty) @@ -3570,7 +3656,9 @@ bfd_byte * default_symfile_relocate (struct objfile *objfile, asection *sectp, bfd_byte *buf) { - bfd *abfd = objfile->obfd; + /* Use sectp->owner instead of objfile->obfd. sectp may point to a + DWO file. */ + bfd *abfd = sectp->owner; /* We're only interested in sections with relocation information. */ @@ -3753,14 +3841,6 @@ for access from GDB.\n\ A load OFFSET may also be given."), &cmdlist); set_cmd_completer (c, filename_completer); - add_setshow_boolean_cmd ("symbol-reloading", class_support, - &symbol_reloading, _("\ -Set dynamic symbol table reloading multiple times in one run."), _("\ -Show dynamic symbol table reloading multiple times in one run."), NULL, - NULL, - show_symbol_reloading, - &setlist, &showlist); - add_prefix_cmd ("overlay", class_support, overlay_command, _("Commands for debugging overlays."), &overlaylist, "overlay ", 0, &cmdlist); diff --git a/contrib/gdb-7/gdb/symfile.h b/contrib/gdb-7/gdb/symfile.h index 604fe16340..6d6b4b8587 100644 --- a/contrib/gdb-7/gdb/symfile.h +++ b/contrib/gdb-7/gdb/symfile.h @@ -1,6 +1,6 @@ /* Definitions for reading symbol files into GDB. - Copyright (C) 1990-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1990-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +22,7 @@ /* This file requires that you first include "bfd.h". */ #include "symtab.h" +#include "probe.h" /* Opaque declarations. */ struct target_section; @@ -29,6 +30,11 @@ struct objfile; struct obj_section; struct obstack; struct block; +struct probe; +struct value; +struct frame_info; +struct agent_expr; +struct axs_value; /* Comparison function for symbol look ups. */ @@ -153,9 +159,10 @@ struct quick_symbol_functions /* Expand and iterate over each "partial" symbol table in OBJFILE where the source file is named NAME. - If there is no '/' in the name, a match after a '/' in the symbol - table's file name will also work. FULL_PATH is the absolute file - name, and REAL_PATH is the same, run through gdb_realpath. + If NAME is not absolute, a match after a '/' in the symbol table's + file name will also work, REAL_PATH is NULL then. If NAME is + absolute then REAL_PATH is non-NULL absolute file name as resolved + via gdb_realpath from NAME. If a match is found, the "partial" symbol table is expanded. Then, this calls iterate_over_some_symtabs (or equivalent) over @@ -163,7 +170,6 @@ struct quick_symbol_functions The result of this call is returned. */ int (*map_symtabs_matching_filename) (struct objfile *objfile, const char *name, - const char *full_path, const char *real_path, int (*callback) (struct symtab *, void *), @@ -176,21 +182,13 @@ struct quick_symbol_functions indicates what sort of symbol to search for. Returns the newly-expanded symbol table in which the symbol is - defined, or NULL if no such symbol table exists. */ + defined, or NULL if no such symbol table exists. If OBJFILE + contains !TYPE_OPAQUE symbol prefer its symtab. If it contains + only TYPE_OPAQUE symbol(s), return at least that symtab. */ struct symtab *(*lookup_symbol) (struct objfile *objfile, int kind, const char *name, domain_enum domain); - /* This is called to expand symbol tables before looking up a - symbol. A backend can choose to implement this and then have its - `lookup_symbol' hook always return NULL, or the reverse. (It - doesn't make sense to implement both.) The arguments are as for - `lookup_symbol'. */ - void (*pre_expand_symtabs_matching) (struct objfile *objfile, - enum block_enum block_kind, - const char *name, - domain_enum domain); - /* Print statistics about any indices loaded for OBJFILE. The statistics should be printed to gdb_stdout. This is used for "maint print statistics". */ @@ -214,16 +212,17 @@ struct quick_symbol_functions /* Read all symbol tables associated with OBJFILE. */ void (*expand_all_symtabs) (struct objfile *objfile); - /* Read all symbol tables associated with OBJFILE which have the - file name FILENAME. + /* Read all symbol tables associated with OBJFILE which have + symtab_to_fullname equal to FULLNAME. This is for the purposes of examining code only, e.g., expand_line_sal. The routine may ignore debug info that is known to not be useful with code, e.g., DW_TAG_type_unit for dwarf debug info. */ - void (*expand_symtabs_with_filename) (struct objfile *objfile, - const char *filename); + void (*expand_symtabs_with_fullname) (struct objfile *objfile, + const char *fullname); /* Return the file name of the file holding the global symbol in OBJFILE - named NAME. If no such symbol exists in OBJFILE, return NULL. */ + named NAME. If no such symbol exists in OBJFILE, return NULL. + Only file extension of returned filename is recognized. */ const char *(*find_symbol_file) (struct objfile *objfile, const char *name); /* Find global or static symbols in all tables that are in NAMESPACE @@ -256,15 +255,14 @@ struct quick_symbol_functions FILE_MATCHER is called for each file in OBJFILE. The file name and the DATA argument are passed to it. If it returns zero, this file is skipped. If FILE_MATCHER is NULL such file is not skipped. + If BASENAMES is non-zero the function should consider only base name of + DATA (passed file name is already only the lbasename part). Otherwise, if KIND does not match this symbol is skipped. - + If even KIND matches, then NAME_MATCHER is called for each symbol - defined in the file. The current language, the symbol name and - DATA are passed to NAME_MATCHER. The symbol "natural" name should - be passed to NAME_MATCHER for all languages except Ada, where - the encoded name is passed instead (see la_symbol_name_compare in - struct language_defn for more details on this). + defined in the file. The symbol "search" name and DATA are passed + to NAME_MATCHER. If NAME_MATCHER returns zero, then this symbol is skipped. @@ -274,8 +272,8 @@ struct quick_symbol_functions functions. */ void (*expand_symtabs_matching) (struct objfile *objfile, - int (*file_matcher) (const char *, void *), - int (*name_matcher) (const struct language_defn *, const char *, void *), + int (*file_matcher) (const char *, void *, int basenames), + int (*name_matcher) (const char *, void *), enum search_domain kind, void *data); @@ -300,6 +298,49 @@ struct quick_symbol_functions int need_fullname); }; +/* Structure of functions used for probe support. If one of these functions + is provided, all must be. */ + +struct sym_probe_fns +{ + /* If non-NULL, return an array of probe objects. + + The returned value does not have to be freed and it has lifetime of the + OBJFILE. */ + VEC (probe_p) *(*sym_get_probes) (struct objfile *); + + /* Return the number of arguments available to PROBE. PROBE will + have come from a call to this objfile's sym_get_probes method. + If you provide an implementation of sym_get_probes, you must + implement this method as well. */ + unsigned (*sym_get_probe_argument_count) (struct probe *probe); + + /* Evaluate the Nth argument available to PROBE. PROBE will have + come from a call to this objfile's sym_get_probes method. N will + be between 0 and the number of arguments available to this probe. + FRAME is the frame in which the evaluation is done; the frame's + PC will match the address of the probe. If you provide an + implementation of sym_get_probes, you must implement this method + as well. */ + struct value *(*sym_evaluate_probe_argument) (struct probe *probe, + unsigned n); + + /* Compile the Nth probe argument to an agent expression. PROBE + will have come from a call to this objfile's sym_get_probes + method. N will be between 0 and the number of arguments + available to this probe. EXPR and VALUE are the agent expression + that is being updated. */ + void (*sym_compile_to_ax) (struct probe *probe, + struct agent_expr *expr, + struct axs_value *value, + unsigned n); + + /* Relocate the probe section of OBJFILE. */ + void (*sym_relocate_probe) (struct objfile *objfile, + struct section_offsets *new_offsets, + struct section_offsets *delta); +}; + /* Structure to keep track of symbol reading functions for various object file types. */ @@ -370,6 +411,10 @@ struct sym_fns bfd_byte *(*sym_relocate) (struct objfile *, asection *sectp, bfd_byte *buf); + /* If non-NULL, this objfile has probe support, and all the probe + functions referred to here will be non-NULL. */ + const struct sym_probe_fns *sym_probe_fns; + /* The "quick" (aka partial) symbol functions for this symbol reader. */ const struct quick_symbol_functions *qf; @@ -402,7 +447,8 @@ extern struct symfile_segment_data *default_symfile_segments (bfd *abfd); extern bfd_byte *default_symfile_relocate (struct objfile *objfile, asection *sectp, bfd_byte *buf); -extern struct symtab *allocate_symtab (const char *, struct objfile *); +extern struct symtab *allocate_symtab (const char *, struct objfile *) + ATTRIBUTE_NONNULL (1); extern void add_symtab_fns (const struct sym_fns *); @@ -463,19 +509,6 @@ extern struct section_addr_info extern void free_section_addr_info (struct section_addr_info *); -/* Make a copy of the string at PTR with SIZE characters in the symbol - obstack (and add a null character at the end in the copy). Returns - the address of the copy. */ - -extern char *obsavestring (const char *, int, struct obstack *); - -/* Concatenate NULL terminated variable argument list of `const char - *' strings; return the new string. Space is found in the OBSTACKP. - Argument list must be terminated by a sentinel expression `(char *) - NULL'. */ - -extern char *obconcat (struct obstack *obstackp, ...) ATTRIBUTE_SENTINEL; - /* Variables */ /* If non-zero, shared library symbols will be added automatically @@ -498,7 +531,7 @@ extern void find_lowest_section (bfd *, asection *, void *); extern bfd *symfile_bfd_open (char *); -extern bfd *bfd_open_maybe_remote (const char *); +extern bfd *gdb_bfd_open_maybe_remote (const char *); extern int get_section_index (struct objfile *, char *); @@ -592,6 +625,7 @@ struct dwarf2_debug_sections { struct dwarf2_section_names str; struct dwarf2_section_names ranges; struct dwarf2_section_names types; + struct dwarf2_section_names addr; struct dwarf2_section_names frame; struct dwarf2_section_names eh_frame; struct dwarf2_section_names gdb_index; @@ -622,13 +656,6 @@ void dwarf2_free_objfile (struct objfile *); /* From mdebugread.c */ -/* Hack to force structures to exist before use in parameter list. */ -struct ecoff_debug_hack -{ - struct ecoff_debug_swap *a; - struct ecoff_debug_info *b; -}; - extern void mdebug_build_psymtabs (struct objfile *, const struct ecoff_debug_swap *, struct ecoff_debug_info *); @@ -637,4 +664,8 @@ extern void elfmdebug_build_psymtabs (struct objfile *, const struct ecoff_debug_swap *, asection *); +/* From minidebug.c. */ + +extern bfd *find_separate_debug_file_in_section (struct objfile *); + #endif /* !defined(SYMFILE_H) */ diff --git a/contrib/gdb-7/gdb/symmisc.c b/contrib/gdb-7/gdb/symmisc.c index daa0b43e19..5fa4e4e0fb 100644 --- a/contrib/gdb-7/gdb/symmisc.c +++ b/contrib/gdb-7/gdb/symmisc.c @@ -1,7 +1,6 @@ /* Do various things to symbol tables (other than lookup), for GDB. - Copyright (C) 1986-2000, 2002-2004, 2007-2012 Free Software - Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -35,6 +34,9 @@ #include "gdb_regex.h" #include "gdb_stat.h" #include "dictionary.h" +#include "typeprint.h" +#include "gdbcmd.h" +#include "source.h" #include "gdb_string.h" #include "readline/readline.h" @@ -85,17 +87,18 @@ print_symbol_bcache_statistics (void) struct program_space *pspace; struct objfile *objfile; - immediate_quit++; ALL_PSPACES (pspace) ALL_PSPACE_OBJFILES (pspace, objfile) { + QUIT; printf_filtered (_("Byte cache statistics for '%s':\n"), objfile->name); print_bcache_statistics (psymbol_bcache_get_bcache (objfile->psymbol_cache), "partial symbol cache"); - print_bcache_statistics (objfile->macro_cache, "preprocessor macro cache"); - print_bcache_statistics (objfile->filename_cache, "file name cache"); + print_bcache_statistics (objfile->per_bfd->macro_cache, + "preprocessor macro cache"); + print_bcache_statistics (objfile->per_bfd->filename_cache, + "file name cache"); } - immediate_quit--; } void @@ -106,10 +109,10 @@ print_objfile_statistics (void) struct symtab *s; int i, linetables, blockvectors; - immediate_quit++; ALL_PSPACES (pspace) ALL_PSPACE_OBJFILES (pspace, objfile) { + QUIT; printf_filtered (_("Statistics for '%s':\n"), objfile->name); if (OBJSTAT (objfile, n_stabs) > 0) printf_filtered (_(" Number of \"stab\" symbols read: %d\n"), @@ -148,15 +151,16 @@ print_objfile_statistics (void) 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 BFD obstack: %d\n"), + obstack_memory_used (&objfile->per_bfd->storage_obstack)); printf_filtered (_(" Total memory used for psymbol cache: %d\n"), bcache_memory_used (psymbol_bcache_get_bcache (objfile->psymbol_cache))); printf_filtered (_(" Total memory used for macro cache: %d\n"), - bcache_memory_used (objfile->macro_cache)); + bcache_memory_used (objfile->per_bfd->macro_cache)); printf_filtered (_(" Total memory used for file name cache: %d\n"), - bcache_memory_used (objfile->filename_cache)); + bcache_memory_used (objfile->per_bfd->filename_cache)); } - immediate_quit--; } static void @@ -182,7 +186,7 @@ dump_objfile (struct objfile *objfile) symtab != NULL; symtab = symtab->next) { - printf_filtered ("%s at ", symtab->filename); + printf_filtered ("%s at ", symtab_to_filename_for_display (symtab)); gdb_print_host_address (symtab, gdb_stdout); printf_filtered (", "); if (symtab->objfile != objfile) @@ -291,7 +295,8 @@ dump_symtab_1 (struct objfile *objfile, struct symtab *symtab, struct block *b; int depth; - fprintf_filtered (outfile, "\nSymtab for file %s\n", symtab->filename); + fprintf_filtered (outfile, "\nSymtab for file %s\n", + symtab_to_filename_for_display (symtab)); if (symtab->dirname) fprintf_filtered (outfile, "Compilation directory is %s\n", symtab->dirname); @@ -353,8 +358,9 @@ dump_symtab_1 (struct objfile *objfile, struct symtab *symtab, } fprintf_filtered (outfile, "\n"); /* Now print each symbol in this block (in no particular order, if - we're using a hashtable). */ - ALL_BLOCK_SYMBOLS (b, iter, sym) + we're using a hashtable). Note that we only want this + block, not any blocks from included symtabs. */ + ALL_DICT_SYMBOLS (BLOCK_DICT (b), iter, sym) { struct print_symbol_args s; @@ -397,7 +403,7 @@ dump_symtab (struct objfile *objfile, struct symtab *symtab, dump_symtab_1 (objfile, symtab, outfile); } -void +static void maintenance_print_symbols (char *args, int from_tty) { char **argv; @@ -436,11 +442,13 @@ maintenance_print_symbols (char *args, int from_tty) perror_with_name (filename); make_cleanup_ui_file_delete (outfile); - immediate_quit++; ALL_SYMTABS (objfile, s) - if (symname == NULL || filename_cmp (symname, s->filename) == 0) - dump_symtab (objfile, s, outfile); - immediate_quit--; + { + QUIT; + if (symname == NULL + || filename_cmp (symname, symtab_to_filename_for_display (s)) == 0) + dump_symtab (objfile, s, outfile); + } do_cleanups (cleanups); } @@ -476,7 +484,8 @@ print_symbol (void *args) { if (TYPE_TAG_NAME (SYMBOL_TYPE (symbol))) { - LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth, + &type_print_raw_options); } else { @@ -486,7 +495,8 @@ print_symbol (void *args) : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT ? "struct" : "union")), SYMBOL_LINKAGE_NAME (symbol)); - LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth, + &type_print_raw_options); } fprintf_filtered (outfile, ";\n"); } @@ -500,7 +510,8 @@ print_symbol (void *args) LA_PRINT_TYPE (SYMBOL_TYPE (symbol), SYMBOL_PRINT_NAME (symbol), outfile, TYPE_CODE (SYMBOL_TYPE (symbol)) != TYPE_CODE_ENUM, - depth); + depth, + &type_print_raw_options); fprintf_filtered (outfile, "; "); } else @@ -509,9 +520,9 @@ print_symbol (void *args) switch (SYMBOL_CLASS (symbol)) { case LOC_CONST: - fprintf_filtered (outfile, "const %ld (0x%lx)", - SYMBOL_VALUE (symbol), - SYMBOL_VALUE (symbol)); + fprintf_filtered (outfile, "const %s (%s)", + plongest (SYMBOL_VALUE (symbol)), + hex_string (SYMBOL_VALUE (symbol))); break; case LOC_CONST_BYTES: @@ -539,28 +550,31 @@ print_symbol (void *args) case LOC_REGISTER: if (SYMBOL_IS_ARGUMENT (symbol)) - fprintf_filtered (outfile, "parameter register %ld", - SYMBOL_VALUE (symbol)); + fprintf_filtered (outfile, "parameter register %s", + plongest (SYMBOL_VALUE (symbol))); else - fprintf_filtered (outfile, "register %ld", SYMBOL_VALUE (symbol)); + fprintf_filtered (outfile, "register %s", + plongest (SYMBOL_VALUE (symbol))); break; case LOC_ARG: - fprintf_filtered (outfile, "arg at offset 0x%lx", - SYMBOL_VALUE (symbol)); + fprintf_filtered (outfile, "arg at offset %s", + hex_string (SYMBOL_VALUE (symbol))); break; case LOC_REF_ARG: - fprintf_filtered (outfile, "reference arg at 0x%lx", SYMBOL_VALUE (symbol)); + fprintf_filtered (outfile, "reference arg at %s", + hex_string (SYMBOL_VALUE (symbol))); break; case LOC_REGPARM_ADDR: - fprintf_filtered (outfile, "address parameter register %ld", SYMBOL_VALUE (symbol)); + fprintf_filtered (outfile, "address parameter register %s", + plongest (SYMBOL_VALUE (symbol))); break; case LOC_LOCAL: - fprintf_filtered (outfile, "local at offset 0x%lx", - SYMBOL_VALUE (symbol)); + fprintf_filtered (outfile, "local at offset %s", + hex_string (SYMBOL_VALUE (symbol))); break; case LOC_TYPEDEF: @@ -615,7 +629,7 @@ print_symbol (void *args) return 1; } -void +static void maintenance_print_msymbols (char *args, int from_tty) { char **argv; @@ -644,7 +658,7 @@ maintenance_print_msymbols (char *args, int from_tty) /* If a second arg is supplied, it is a source file name to match on. */ if (argv[1] != NULL) { - symname = xfullpath (argv[1]); + symname = gdb_realpath (argv[1]); make_cleanup (xfree, symname); if (symname && stat (symname, &sym_st)) perror_with_name (symname); @@ -659,18 +673,20 @@ maintenance_print_msymbols (char *args, int from_tty) perror_with_name (filename); make_cleanup_ui_file_delete (outfile); - immediate_quit++; ALL_PSPACES (pspace) ALL_PSPACE_OBJFILES (pspace, objfile) - if (symname == NULL || (!stat (objfile->name, &obj_st) - && sym_st.st_ino == obj_st.st_ino)) - dump_msymbols (objfile, outfile); - immediate_quit--; + { + QUIT; + if (symname == NULL || (!stat (objfile->name, &obj_st) + && sym_st.st_dev == obj_st.st_dev + && sym_st.st_ino == obj_st.st_ino)) + dump_msymbols (objfile, outfile); + } fprintf_filtered (outfile, "\n\n"); do_cleanups (cleanups); } -void +static void maintenance_print_objfiles (char *ignore, int from_tty) { struct program_space *pspace; @@ -678,16 +694,17 @@ maintenance_print_objfiles (char *ignore, int from_tty) dont_repeat (); - immediate_quit++; ALL_PSPACES (pspace) ALL_PSPACE_OBJFILES (pspace, objfile) - dump_objfile (objfile); - immediate_quit--; + { + QUIT; + dump_objfile (objfile); + } } - /* List all the symbol tables whose names match REGEXP (optional). */ -void + +static void maintenance_info_symtabs (char *regexp, int from_tty) { struct program_space *pspace; @@ -710,7 +727,7 @@ maintenance_info_symtabs (char *regexp, int from_tty) QUIT; if (! regexp - || re_exec (symtab->filename)) + || re_exec (symtab_to_filename_for_display (symtab))) { if (! printed_objfile_start) { @@ -721,7 +738,8 @@ maintenance_info_symtabs (char *regexp, int from_tty) printed_objfile_start = 1; } - printf_filtered (" { symtab %s ", symtab->filename); + printf_filtered (" { symtab %s ", + symtab_to_filename_for_display (symtab)); wrap_here (" "); printf_filtered ("((struct symtab *) %s)\n", host_address_to_string (symtab)); @@ -764,10 +782,34 @@ block_depth (struct block *block) /* Do early runtime initializations. */ + void _initialize_symmisc (void) { std_in = stdin; std_out = stdout; std_err = stderr; + + add_cmd ("symbols", class_maintenance, maintenance_print_symbols, _("\ +Print dump of current symbol definitions.\n\ +Entries in the full symbol table are dumped to file OUTFILE.\n\ +If a SOURCE file is specified, dump only that file's symbols."), + &maintenanceprintlist); + + add_cmd ("msymbols", class_maintenance, maintenance_print_msymbols, _("\ +Print dump of current minimal symbol definitions.\n\ +Entries in the minimal symbol table are dumped to file OUTFILE.\n\ +If a SOURCE file is specified, dump only that file's minimal symbols."), + &maintenanceprintlist); + + add_cmd ("objfiles", class_maintenance, maintenance_print_objfiles, + _("Print dump of current object file definitions."), + &maintenanceprintlist); + + add_cmd ("symtabs", class_maintenance, maintenance_info_symtabs, _("\ +List the full symbol tables for all object files.\n\ +This does not include information about individual symbols, blocks, or\n\ +linetables --- just the symbol table structures themselves.\n\ +With an argument REGEXP, list the symbol tables whose names that match that."), + &maintenanceinfolist); } diff --git a/contrib/gdb-7/gdb/symtab.c b/contrib/gdb-7/gdb/symtab.c index ab6a1aa40c..c0e588455e 100644 --- a/contrib/gdb-7/gdb/symtab.c +++ b/contrib/gdb-7/gdb/symtab.c @@ -1,6 +1,6 @@ /* Symbol table lookup for the GNU debugger, GDB. - Copyright (C) 1986-2004, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -27,20 +27,20 @@ #include "symfile.h" #include "objfiles.h" #include "gdbcmd.h" -#include "call-cmds.h" #include "gdb_regex.h" #include "expression.h" #include "language.h" #include "demangle.h" #include "inferior.h" -#include "linespec.h" #include "source.h" #include "filenames.h" /* for FILENAME_CMP */ #include "objc-lang.h" #include "d-lang.h" #include "ada-lang.h" +#include "go-lang.h" #include "p-lang.h" #include "addrmap.h" +#include "cli/cli-utils.h" #include "hashtab.h" @@ -62,11 +62,10 @@ #include "macroscope.h" #include "psymtab.h" +#include "parser-defs.h" /* Prototypes for local functions */ -static void completion_list_add_name (char *, char *, int, char *, char *); - static void rbreak_command (char *, int); static void types_info (char *, int); @@ -77,15 +76,13 @@ static void variables_info (char *, int); static void sources_info (char *, int); -static void output_source_filename (const char *, int *); - static int find_line_common (struct linetable *, int, int *, int); static struct symbol *lookup_symbol_aux (const char *name, const struct block *block, const domain_enum domain, enum language language, - int *is_a_field_of_this); + struct field_of_this_result *is_a_field_of_this); static struct symbol *lookup_symbol_aux_local (const char *name, @@ -110,6 +107,9 @@ void _initialize_symtab (void); /* */ +/* When non-zero, print debugging messages related to symtab creation. */ +int symtab_create_debug = 0; + /* Non-zero if a file may be known by two different basenames. This is the uncommon case, and significantly slows down gdb. Default set to "off" to not slow down the common case. */ @@ -122,7 +122,7 @@ int basenames_may_differ = 0; const char multiple_symbols_ask[] = "ask"; const char multiple_symbols_all[] = "all"; const char multiple_symbols_cancel[] = "cancel"; -static const char *multiple_symbols_modes[] = +static const char *const multiple_symbols_modes[] = { multiple_symbols_ask, multiple_symbols_all, @@ -145,10 +145,48 @@ multiple_symbols_select_mode (void) const struct block *block_found; +/* See whether FILENAME matches SEARCH_NAME using the rule that we + advertise to the user. (The manual's description of linespecs + describes what we advertise). Returns true if they match, false + otherwise. */ + +int +compare_filenames_for_search (const char *filename, const char *search_name) +{ + int len = strlen (filename); + size_t search_len = strlen (search_name); + + if (len < search_len) + return 0; + + /* The tail of FILENAME must match. */ + if (FILENAME_CMP (filename + len - search_len, search_name) != 0) + return 0; + + /* Either the names must completely match, or the character + preceding the trailing SEARCH_NAME segment of FILENAME must be a + directory separator. + + The check !IS_ABSOLUTE_PATH ensures SEARCH_NAME "/dir/file.c" + cannot match FILENAME "/path//dir/file.c" - as user has requested + absolute path. The sama applies for "c:\file.c" possibly + incorrectly hypothetically matching "d:\dir\c:\file.c". + + The HAS_DRIVE_SPEC purpose is to make FILENAME "c:file.c" + compatible with SEARCH_NAME "file.c". In such case a compiler had + to put the "c:file.c" name into debug info. Such compatibility + works only on GDB built for DOS host. */ + return (len == search_len + || (!IS_ABSOLUTE_PATH (search_name) + && IS_DIR_SEPARATOR (filename[len - search_len - 1])) + || (HAS_DRIVE_SPEC (filename) + && STRIP_DRIVE_SPEC (filename) == &filename[len - search_len])); +} + /* Check for a symtab of a specific name by searching some symtabs. This is a helper function for callbacks of iterate_over_symtabs. - The return value, NAME, FULL_PATH, REAL_PATH, CALLBACK, and DATA + The return value, NAME, REAL_PATH, CALLBACK, and DATA are identical to the `map_symtabs_matching_filename' method of quick_symbol_functions. @@ -158,7 +196,6 @@ const struct block *block_found; int iterate_over_some_symtabs (const char *name, - const char *full_path, const char *real_path, int (*callback) (struct symtab *symtab, void *data), @@ -167,12 +204,11 @@ iterate_over_some_symtabs (const char *name, struct symtab *after_last) { struct symtab *s = NULL; - struct cleanup *cleanup; const char* base_name = lbasename (name); for (s = first; s != NULL && s != after_last; s = s->next) { - if (FILENAME_CMP (name, s->filename) == 0) + if (compare_filenames_for_search (s->filename, name)) { if (callback (s, data)) return 1; @@ -184,52 +220,29 @@ iterate_over_some_symtabs (const char *name, && FILENAME_CMP (base_name, lbasename (s->filename)) != 0) continue; + if (compare_filenames_for_search (symtab_to_fullname (s), name)) + { + if (callback (s, data)) + return 1; + } + /* If the user gave us an absolute path, try to find the file in this symtab and use its absolute path. */ - if (full_path != NULL) + if (real_path != NULL) { - const char *fp = symtab_to_fullname (s); + const char *fullname = symtab_to_fullname (s); - if (fp != NULL && FILENAME_CMP (full_path, fp) == 0) - { + gdb_assert (IS_ABSOLUTE_PATH (real_path)); + gdb_assert (IS_ABSOLUTE_PATH (name)); + if (FILENAME_CMP (real_path, fullname) == 0) + { if (callback (s, data)) return 1; - } - } - - if (real_path != NULL) - { - char *fullname = symtab_to_fullname (s); - - if (fullname != NULL) - { - char *rp = gdb_realpath (fullname); - - make_cleanup (xfree, rp); - if (FILENAME_CMP (real_path, rp) == 0) - { - if (callback (s, data)) - return 1; - } - } + } } } - /* Now, search for a matching tail (only if name doesn't have any dirs). */ - - if (lbasename (name) == name) - { - for (s = first; s != NULL && s != after_last; s = s->next) - { - if (FILENAME_CMP (lbasename (s->filename), name) == 0) - { - if (callback (s, data)) - return 1; - } - } - } - return 0; } @@ -246,25 +259,22 @@ iterate_over_symtabs (const char *name, void *data), void *data) { - struct symtab *s = NULL; struct objfile *objfile; char *real_path = NULL; - char *full_path = NULL; struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); /* Here we are interested in canonicalizing an absolute path, not absolutizing a relative path. */ if (IS_ABSOLUTE_PATH (name)) { - full_path = xfullpath (name); - make_cleanup (xfree, full_path); real_path = gdb_realpath (name); make_cleanup (xfree, real_path); + gdb_assert (IS_ABSOLUTE_PATH (real_path)); } ALL_OBJFILES (objfile) { - if (iterate_over_some_symtabs (name, full_path, real_path, callback, data, + if (iterate_over_some_symtabs (name, real_path, callback, data, objfile->symtabs, NULL)) { do_cleanups (cleanups); @@ -280,7 +290,6 @@ iterate_over_symtabs (const char *name, if (objfile->sf && objfile->sf->qf->map_symtabs_matching_filename (objfile, name, - full_path, real_path, callback, data)) @@ -329,9 +338,9 @@ gdb_mangle_name (struct type *type, int method_id, int signature_id) char *mangled_name; struct fn_field *f = TYPE_FN_FIELDLIST1 (type, method_id); struct fn_field *method = &f[signature_id]; - char *field_name = TYPE_FN_FIELDLIST_NAME (type, method_id); + const char *field_name = TYPE_FN_FIELDLIST_NAME (type, method_id); const char *physname = TYPE_FN_FIELD_PHYSNAME (f, signature_id); - char *newname = type_name_no_tag (type); + const char *newname = type_name_no_tag (type); /* Does the form of physname indicate that it is the full mangled name of a constructor (not just the args)? */ @@ -368,19 +377,20 @@ gdb_mangle_name (struct type *type, int method_id, int signature_id) if (len == 0) { - sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + xsnprintf (buf, sizeof (buf), "__%s%s", const_prefix, volatile_prefix); } else if (physname[0] == 't' || physname[0] == 'Q') { /* The physname for template and qualified methods already includes the class name. */ - sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + xsnprintf (buf, sizeof (buf), "__%s%s", const_prefix, volatile_prefix); newname = NULL; len = 0; } else { - sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); + xsnprintf (buf, sizeof (buf), "__%s%s%d", const_prefix, + volatile_prefix, len); } mangled_name_len = ((is_constructor ? 0 : strlen (field_name)) + strlen (buf) + len + strlen (physname) + 1); @@ -422,9 +432,10 @@ symbol_init_cplus_specific (struct general_symbol_info *gsymbol, correctly allocated. For C++ symbols a cplus_specific struct is allocated so OBJFILE must not be NULL. If this is a non C++ symbol OBJFILE can be NULL. */ + void symbol_set_demangled_name (struct general_symbol_info *gsymbol, - char *name, + const char *name, struct objfile *objfile) { if (gsymbol->language == language_cplus) @@ -439,7 +450,8 @@ symbol_set_demangled_name (struct general_symbol_info *gsymbol, } /* Return the demangled name of GSYMBOL. */ -char * + +const char * symbol_get_demangled_name (const struct general_symbol_info *gsymbol) { if (gsymbol->language == language_cplus) @@ -456,12 +468,14 @@ symbol_get_demangled_name (const struct general_symbol_info *gsymbol) /* Initialize the language dependent portion of a symbol depending upon the language for the symbol. */ + void symbol_set_language (struct general_symbol_info *gsymbol, enum language language) { gsymbol->language = language; if (gsymbol->language == language_d + || gsymbol->language == language_go || gsymbol->language == language_java || gsymbol->language == language_objc || gsymbol->language == language_fortran) @@ -482,11 +496,12 @@ symbol_set_language (struct general_symbol_info *gsymbol, /* Objects of this type are stored in the demangled name hash table. */ struct demangled_name_entry { - char *mangled; + const char *mangled; char demangled[1]; }; /* Hash function for the demangled name hash. */ + static hashval_t hash_demangled_name_entry (const void *data) { @@ -496,6 +511,7 @@ hash_demangled_name_entry (const void *data) } /* Equality function for the demangled name hash. */ + static int eq_demangled_name_entry (const void *a, const void *b) { @@ -580,6 +596,22 @@ symbol_find_demangled_name (struct general_symbol_info *gsymbol, return demangled; } } + /* FIXME(dje): Continually adding languages here is clumsy. + Better to just call la_demangle if !auto, and if auto then call + a utility routine that tries successive languages in turn and reports + which one it finds. I realize the la_demangle options may be different + for different languages but there's already a FIXME for that. */ + if (gsymbol->language == language_go + || gsymbol->language == language_auto) + { + demangled = go_demangle (mangled, 0); + if (demangled != NULL) + { + gsymbol->language = language_go; + return demangled; + } + } + /* We could support `gsymbol->language == language_fortran' here to provide module namespaces also for inferiors with only minimal symbol table (ELF symbols). Just the mangling standard is not standardized across compilers @@ -644,12 +676,14 @@ symbol_set_names (struct general_symbol_info *gsymbol, name with the symbol, we don't need to use the same trick as Java. */ if (!copy_name) - gsymbol->name = (char *) linkage_name; + gsymbol->name = linkage_name; else { - gsymbol->name = obstack_alloc (&objfile->objfile_obstack, len + 1); - memcpy (gsymbol->name, linkage_name, len); - gsymbol->name[len] = '\0'; + char *name = obstack_alloc (&objfile->objfile_obstack, len + 1); + + memcpy (name, linkage_name, len); + name[len] = '\0'; + gsymbol->name = name; } symbol_set_demangled_name (gsymbol, NULL, NULL); @@ -694,13 +728,17 @@ symbol_set_names (struct general_symbol_info *gsymbol, linkage_name_copy = linkage_name; } - entry.mangled = (char *) lookup_name; + entry.mangled = lookup_name; slot = ((struct demangled_name_entry **) htab_find_slot (objfile->demangled_names_hash, &entry, INSERT)); /* If this name is not in the hash table, add it. */ - if (*slot == NULL) + if (*slot == NULL + /* A C version of the symbol may have already snuck into the table. + This happens to, e.g., main.init (__go_init_main). Cope. */ + || (gsymbol->language == language_go + && (*slot)->demangled[0] == '\0')) { char *demangled_name = symbol_find_demangled_name (gsymbol, linkage_name_copy); @@ -721,10 +759,12 @@ symbol_set_names (struct general_symbol_info *gsymbol, offsetof (struct demangled_name_entry, demangled) + demangled_len + 1); - (*slot)->mangled = (char *) lookup_name; + (*slot)->mangled = lookup_name; } else { + char *mangled_ptr; + /* If we must copy the mangled name, put it directly after the demangled name so we can have a single allocation. */ @@ -732,8 +772,9 @@ symbol_set_names (struct general_symbol_info *gsymbol, offsetof (struct demangled_name_entry, demangled) + lookup_len + demangled_len + 2); - (*slot)->mangled = &((*slot)->demangled[demangled_len + 1]); - strcpy ((*slot)->mangled, lookup_name); + mangled_ptr = &((*slot)->demangled[demangled_len + 1]); + strcpy (mangled_ptr, lookup_name); + (*slot)->mangled = mangled_ptr; } if (demangled_name != NULL) @@ -755,13 +796,14 @@ symbol_set_names (struct general_symbol_info *gsymbol, /* Return the source code name of a symbol. In languages where demangling is necessary, this is the demangled name. */ -char * +const char * symbol_natural_name (const struct general_symbol_info *gsymbol) { switch (gsymbol->language) { case language_cplus: case language_d: + case language_go: case language_java: case language_objc: case language_fortran: @@ -782,36 +824,39 @@ symbol_natural_name (const struct general_symbol_info *gsymbol) /* Return the demangled name for a symbol based on the language for that symbol. If no demangled name exists, return NULL. */ -char * + +const char * symbol_demangled_name (const struct general_symbol_info *gsymbol) { + const char *dem_name = NULL; + switch (gsymbol->language) { case language_cplus: case language_d: + case language_go: case language_java: case language_objc: case language_fortran: - if (symbol_get_demangled_name (gsymbol) != NULL) - return symbol_get_demangled_name (gsymbol); + dem_name = symbol_get_demangled_name (gsymbol); break; case language_ada: - if (symbol_get_demangled_name (gsymbol) != NULL) - return symbol_get_demangled_name (gsymbol); - else - return ada_decode_symbol (gsymbol); + dem_name = symbol_get_demangled_name (gsymbol); + if (dem_name == NULL) + dem_name = ada_decode_symbol (gsymbol); break; default: break; } - return NULL; + return dem_name; } /* Return the search name of a symbol---generally the demangled or linkage name of the symbol, depending on how it will be searched for. If there is no distinct demangled name, then returns the same value (same pointer) as SYMBOL_LINKAGE_NAME. */ -char * + +const char * symbol_search_name (const struct general_symbol_info *gsymbol) { if (gsymbol->language == language_ada) @@ -821,6 +866,7 @@ symbol_search_name (const struct general_symbol_info *gsymbol) } /* Initialize the structure fields to zero values. */ + void init_sal (struct symtab_and_line *sal) { @@ -832,6 +878,7 @@ init_sal (struct symtab_and_line *sal) sal->end = 0; sal->explicit_pc = 0; sal->explicit_line = 0; + sal->probe = NULL; } @@ -1078,7 +1125,7 @@ demangle_for_lookup (const char *name, enum language lang, modified_name = name; - /* If we are using C++, D, or Java, demangle the name before doing a + /* If we are using C++, D, Go, or Java, demangle the name before doing a lookup, so we can always binary search. */ if (lang == language_cplus) { @@ -1119,6 +1166,15 @@ demangle_for_lookup (const char *name, enum language lang, make_cleanup (xfree, demangled_name); } } + else if (lang == language_go) + { + demangled_name = go_demangle (name, 0); + if (demangled_name) + { + modified_name = demangled_name; + make_cleanup (xfree, demangled_name); + } + } *result_name = modified_name; return cleanup; @@ -1133,11 +1189,11 @@ demangle_for_lookup (const char *name, enum language lang, BLOCK_FOUND is set to the block in which NAME is found (in the case of a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */ -/* This function has a bunch of loops in it and it would seem to be - attractive to put in some QUIT's (though I'm not really sure - whether it can run long enough to be really important). But there +/* This function (or rather its subordinates) have a bunch of loops and + it would seem to be attractive to put in some QUIT's (though I'm not really + sure whether it can run long enough to be really important). But there are a few calls for which it would appear to be bad news to quit - out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note + out of here: e.g., find_proc_desc in alpha-mdebug-tdep.c. (Note that there is C++ code below which can error(), but that probably doesn't affect these calls since they are looking for a known variable and thus can probably assume it will never hit the C++ @@ -1146,7 +1202,7 @@ demangle_for_lookup (const char *name, enum language lang, struct symbol * lookup_symbol_in_language (const char *name, const struct block *block, const domain_enum domain, enum language lang, - int *is_a_field_of_this) + struct field_of_this_result *is_a_field_of_this) { const char *modified_name; struct symbol *returnval; @@ -1164,7 +1220,8 @@ lookup_symbol_in_language (const char *name, const struct block *block, struct symbol * lookup_symbol (const char *name, const struct block *block, - domain_enum domain, int *is_a_field_of_this) + domain_enum domain, + struct field_of_this_result *is_a_field_of_this) { return lookup_symbol_in_language (name, block, domain, current_language->la_language, @@ -1187,7 +1244,10 @@ lookup_language_this (const struct language_defn *lang, sym = lookup_block_symbol (block, lang->la_name_of_this, VAR_DOMAIN); if (sym != NULL) - return sym; + { + block_found = block; + return sym; + } if (BLOCK_FUNCTION (block)) break; block = BLOCK_SUPERBLOCK (block); @@ -1196,26 +1256,68 @@ lookup_language_this (const struct language_defn *lang, return NULL; } +/* Given TYPE, a structure/union, + return 1 if the component named NAME from the ultimate target + structure/union is defined, otherwise, return 0. */ + +static int +check_field (struct type *type, const char *name, + struct field_of_this_result *is_a_field_of_this) +{ + int i; + + /* The type may be a stub. */ + CHECK_TYPEDEF (type); + + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + const char *t_field_name = TYPE_FIELD_NAME (type, i); + + if (t_field_name && (strcmp_iw (t_field_name, name) == 0)) + { + is_a_field_of_this->type = type; + is_a_field_of_this->field = &TYPE_FIELD (type, i); + return 1; + } + } + + /* C++: If it was not found as a data field, then try to return it + as a pointer to a method. */ + + for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i) + { + if (strcmp_iw (TYPE_FN_FIELDLIST_NAME (type, i), name) == 0) + { + is_a_field_of_this->type = type; + is_a_field_of_this->fn_field = &TYPE_FN_FIELDLIST (type, i); + return 1; + } + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + if (check_field (TYPE_BASECLASS (type, i), name, is_a_field_of_this)) + return 1; + + return 0; +} + /* Behave like lookup_symbol except that NAME is the natural name - of the symbol that we're looking for and, if LINKAGE_NAME is - non-NULL, ensure that the symbol's linkage name matches as - well. */ + (e.g., demangled name) of the symbol that we're looking for. */ static struct symbol * lookup_symbol_aux (const char *name, const struct block *block, const domain_enum domain, enum language language, - int *is_a_field_of_this) + struct field_of_this_result *is_a_field_of_this) { struct symbol *sym; const struct language_defn *langdef; /* Make sure we do something sensible with is_a_field_of_this, since the callers that set this parameter to some non-null value will - certainly use it later and expect it to be either 0 or 1. - If we don't set it, the contents of is_a_field_of_this are - undefined. */ + certainly use it later. If we don't set it, the contents of + is_a_field_of_this are undefined. */ if (is_a_field_of_this != NULL) - *is_a_field_of_this = 0; + memset (is_a_field_of_this, 0, sizeof (*is_a_field_of_this)); /* Search specified block and its superiors. Don't search STATIC_BLOCK or GLOBAL_BLOCK. */ @@ -1229,7 +1331,10 @@ lookup_symbol_aux (const char *name, const struct block *block, langdef = language_def (language); - if (is_a_field_of_this != NULL) + /* Don't do this check if we are searching for a struct. It will + not be found by check_field, but will be found by other + means. */ + if (is_a_field_of_this != NULL && domain != STRUCT_DOMAIN) { struct symbol *sym = lookup_language_this (langdef, block); @@ -1249,11 +1354,8 @@ lookup_symbol_aux (const char *name, const struct block *block, error (_("Internal error: `%s' is not an aggregate"), langdef->la_name_of_this); - if (check_field (t, name)) - { - *is_a_field_of_this = 1; - return NULL; - } + if (check_field (t, name, is_a_field_of_this)) + return NULL; } } @@ -1399,17 +1501,17 @@ lookup_global_symbol_from_objfile (const struct objfile *main_objfile, objfile = objfile_separate_debug_iterate (main_objfile, objfile)) { /* Go through symtabs. */ - ALL_OBJFILE_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, domain); - if (sym) - { - block_found = block; - return fixup_symbol_section (sym, (struct objfile *)objfile); - } - } + ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, domain); + if (sym) + { + block_found = block; + return fixup_symbol_section (sym, (struct objfile *)objfile); + } + } sym = lookup_symbol_aux_quick ((struct objfile *) objfile, GLOBAL_BLOCK, name, domain); @@ -1420,42 +1522,94 @@ lookup_global_symbol_from_objfile (const struct objfile *main_objfile, return NULL; } -/* Check to see if the symbol is defined in one of the symtabs. - BLOCK_INDEX should be either GLOBAL_BLOCK or STATIC_BLOCK, +/* Check to see if the symbol is defined in one of the OBJFILE's + symtabs. BLOCK_INDEX should be either GLOBAL_BLOCK or STATIC_BLOCK, depending on whether or not we want to search global symbols or static symbols. */ +static struct symbol * +lookup_symbol_aux_objfile (struct objfile *objfile, int block_index, + const char *name, const domain_enum domain) +{ + struct symbol *sym = NULL; + struct blockvector *bv; + const struct block *block; + struct symtab *s; + + ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, block_index); + sym = lookup_block_symbol (block, name, domain); + if (sym) + { + block_found = block; + return fixup_symbol_section (sym, objfile); + } + } + + return NULL; +} + +/* Same as lookup_symbol_aux_objfile, except that it searches all + objfiles. Return the first match found. */ + static struct symbol * lookup_symbol_aux_symtabs (int block_index, const char *name, const domain_enum domain) { struct symbol *sym; struct objfile *objfile; - struct blockvector *bv; - const struct block *block; - struct symtab *s; ALL_OBJFILES (objfile) { - if (objfile->sf) - objfile->sf->qf->pre_expand_symtabs_matching (objfile, - block_index, - name, domain); + sym = lookup_symbol_aux_objfile (objfile, block_index, name, domain); + if (sym) + return sym; + } + + return NULL; +} + +/* Wrapper around lookup_symbol_aux_objfile for search_symbols. + Look up LINKAGE_NAME in DOMAIN in the global and static blocks of OBJFILE + and all related objfiles. */ + +static struct symbol * +lookup_symbol_in_objfile_from_linkage_name (struct objfile *objfile, + const char *linkage_name, + domain_enum domain) +{ + enum language lang = current_language->la_language; + const char *modified_name; + struct cleanup *cleanup = demangle_for_lookup (linkage_name, lang, + &modified_name); + struct objfile *main_objfile, *cur_objfile; + + if (objfile->separate_debug_objfile_backlink) + main_objfile = objfile->separate_debug_objfile_backlink; + else + main_objfile = objfile; - ALL_OBJFILE_SYMTABS (objfile, s) - if (s->primary) + for (cur_objfile = main_objfile; + cur_objfile; + cur_objfile = objfile_separate_debug_iterate (main_objfile, cur_objfile)) + { + struct symbol *sym; + + sym = lookup_symbol_aux_objfile (cur_objfile, GLOBAL_BLOCK, + modified_name, domain); + if (sym == NULL) + sym = lookup_symbol_aux_objfile (cur_objfile, STATIC_BLOCK, + modified_name, domain); + if (sym != NULL) { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, block_index); - sym = lookup_block_symbol (block, name, domain); - if (sym) - { - block_found = block; - return fixup_symbol_section (sym, objfile); - } + do_cleanups (cleanup); + return sym; } - } + } + do_cleanups (cleanup); return NULL; } @@ -1503,7 +1657,7 @@ Internal: %s symbol `%s' found in %s psymtab but not in symtab.\n\ %s may be an inlined function, or may be a template function\n\ (if a template, try specifying an instantiation: %s)."), kind == GLOBAL_BLOCK ? "global" : "static", - name, symtab->filename, name, name); + name, symtab_to_filename_for_display (symtab), name, name); } return fixup_symbol_section (sym, objfile); } @@ -1570,6 +1724,46 @@ lookup_symbol_static (const char *name, return NULL; } +/* Private data to be used with lookup_symbol_global_iterator_cb. */ + +struct global_sym_lookup_data +{ + /* The name of the symbol we are searching for. */ + const char *name; + + /* The domain to use for our search. */ + domain_enum domain; + + /* The field where the callback should store the symbol if found. + It should be initialized to NULL before the search is started. */ + struct symbol *result; +}; + +/* A callback function for gdbarch_iterate_over_objfiles_in_search_order. + It searches by name for a symbol in the GLOBAL_BLOCK of the given + OBJFILE. The arguments for the search are passed via CB_DATA, + which in reality is a pointer to struct global_sym_lookup_data. */ + +static int +lookup_symbol_global_iterator_cb (struct objfile *objfile, + void *cb_data) +{ + struct global_sym_lookup_data *data = + (struct global_sym_lookup_data *) cb_data; + + gdb_assert (data->result == NULL); + + data->result = lookup_symbol_aux_objfile (objfile, GLOBAL_BLOCK, + data->name, data->domain); + if (data->result == NULL) + data->result = lookup_symbol_aux_quick (objfile, GLOBAL_BLOCK, + data->name, data->domain); + + /* If we found a match, tell the iterator to stop. Otherwise, + keep going. */ + return (data->result != NULL); +} + /* Lookup a symbol in all files' global blocks (searching psymtabs if necessary). */ @@ -1580,6 +1774,7 @@ lookup_symbol_global (const char *name, { struct symbol *sym = NULL; struct objfile *objfile = NULL; + struct global_sym_lookup_data lookup_data; /* Call library-specific lookup procedure. */ objfile = lookup_objfile_from_block (block); @@ -1588,18 +1783,14 @@ lookup_symbol_global (const char *name, if (sym != NULL) return sym; - sym = lookup_symbol_aux_symtabs (GLOBAL_BLOCK, name, domain); - if (sym != NULL) - return sym; - - ALL_OBJFILES (objfile) - { - sym = lookup_symbol_aux_quick (objfile, GLOBAL_BLOCK, name, domain); - if (sym) - return sym; - } + memset (&lookup_data, 0, sizeof (lookup_data)); + lookup_data.name = name; + lookup_data.domain = domain; + gdbarch_iterate_over_objfiles_in_search_order + (objfile != NULL ? get_objfile_arch (objfile) : target_gdbarch (), + lookup_symbol_global_iterator_cb, &lookup_data, objfile); - return NULL; + return lookup_data.result; } int @@ -1671,7 +1862,7 @@ basic_lookup_transparent_type_quick (struct objfile *objfile, int kind, Internal: global symbol `%s' found in %s psymtab but not in symtab.\n\ %s may be an inlined function, or may be a template function\n\ (if a template, try specifying an instantiation: %s)."), - name, symtab->filename, name, name); + name, symtab_to_filename_for_display (symtab), name, name); } if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) return SYMBOL_TYPE (sym); @@ -1702,22 +1893,16 @@ basic_lookup_transparent_type (const char *name) ALL_OBJFILES (objfile) { - if (objfile->sf) - objfile->sf->qf->pre_expand_symtabs_matching (objfile, - GLOBAL_BLOCK, - name, STRUCT_DOMAIN); - - ALL_OBJFILE_SYMTABS (objfile, s) - if (s->primary) - { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); - if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) - { - return SYMBOL_TYPE (sym); - } - } + ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); + if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) + { + return SYMBOL_TYPE (sym); + } + } } ALL_OBJFILES (objfile) @@ -1736,11 +1921,7 @@ basic_lookup_transparent_type (const char *name) ALL_OBJFILES (objfile) { - if (objfile->sf) - objfile->sf->qf->pre_expand_symtabs_matching (objfile, STATIC_BLOCK, - name, STRUCT_DOMAIN); - - ALL_OBJFILE_SYMTABS (objfile, s) + ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s) { bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); @@ -1762,7 +1943,6 @@ basic_lookup_transparent_type (const char *name) return (struct type *) 0; } - /* Find the name of the file containing main(). */ /* FIXME: What about languages without main() or specially linked executables that have no main() ? */ @@ -1801,14 +1981,14 @@ struct symbol * lookup_block_symbol (const struct block *block, const char *name, const domain_enum domain) { - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym; if (!BLOCK_FUNCTION (block)) { - for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter); + for (sym = block_iter_name_first (block, name, &iter); sym != NULL; - sym = dict_iter_name_next (name, &iter)) + sym = block_iter_name_next (name, &iter)) { if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), SYMBOL_DOMAIN (sym), domain)) @@ -1826,9 +2006,9 @@ lookup_block_symbol (const struct block *block, const char *name, struct symbol *sym_found = NULL; - for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter); + for (sym = block_iter_name_first (block, name, &iter); sym != NULL; - sym = dict_iter_name_next (name, &iter)) + sym = block_iter_name_next (name, &iter)) { if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), SYMBOL_DOMAIN (sym), domain)) @@ -1844,41 +2024,33 @@ lookup_block_symbol (const struct block *block, const char *name, } } -/* Iterate over the symbols named NAME, matching DOMAIN, starting with - BLOCK. +/* Iterate over the symbols named NAME, matching DOMAIN, in BLOCK. For each symbol that matches, CALLBACK is called. The symbol and DATA are passed to the callback. If CALLBACK returns zero, the iteration ends. Otherwise, the - search continues. This function iterates upward through blocks. - When the outermost block has been finished, the function - returns. */ + search continues. */ void iterate_over_symbols (const struct block *block, const char *name, const domain_enum domain, - int (*callback) (struct symbol *, void *), + symbol_found_callback_ftype *callback, void *data) { - while (block) - { - struct dict_iterator iter; - struct symbol *sym; + struct block_iterator iter; + struct symbol *sym; - for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter); - sym != NULL; - sym = dict_iter_name_next (name, &iter)) + for (sym = block_iter_name_first (block, name, &iter); + sym != NULL; + sym = block_iter_name_next (name, &iter)) + { + if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), + SYMBOL_DOMAIN (sym), domain)) { - if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), - SYMBOL_DOMAIN (sym), domain)) - { - if (!callback (sym, data)) - return; - } + if (!callback (sym, data)) + return; } - - block = BLOCK_SUPERBLOCK (block); } } @@ -1893,12 +2065,9 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section) struct symtab *s = NULL; struct symtab *best_s = NULL; struct objfile *objfile; - struct program_space *pspace; CORE_ADDR distance = 0; struct minimal_symbol *msymbol; - pspace = current_program_space; - /* If we know that this is not a text address, return failure. This is necessary because we loop based on the block's high and low code addresses, which do not include the data ranges, and because @@ -1958,7 +2127,7 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section) } if (section != 0) { - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym = NULL; ALL_BLOCK_SYMBOLS (b, iter, sym) @@ -1979,6 +2148,8 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section) if (best_s != NULL) return (best_s); + /* Not found in symtabs, search the "quick" symtabs (e.g. psymtabs). */ + ALL_OBJFILES (objfile) { struct symtab *result; @@ -2049,7 +2220,6 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) we will use a line one less than this, with a range from the start of that file to the first line's pc. */ struct linetable_entry *alt = NULL; - struct symtab *alt_symtab = 0; /* Info on best line seen in this file. */ @@ -2194,10 +2364,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) /* Is this file's first line closer than the first lines of other files? If so, record this file, and its first line, as best alternate. */ if (item->pc > pc && (!alt || item->pc < alt->pc)) - { - alt = item; - alt_symtab = s; - } + alt = item; for (i = 0; i < len; i++, item++) { @@ -2333,13 +2500,10 @@ find_line_symtab (struct symtab *symtab, int line, ALL_OBJFILES (objfile) { if (objfile->sf) - objfile->sf->qf->expand_symtabs_with_filename (objfile, - symtab->filename); + objfile->sf->qf->expand_symtabs_with_fullname (objfile, + symtab_to_fullname (symtab)); } - /* Get symbol full file name if possible. */ - symtab_to_fullname (symtab); - ALL_SYMTABS (objfile, s) { struct linetable *l; @@ -2347,9 +2511,8 @@ find_line_symtab (struct symtab *symtab, int line, if (FILENAME_CMP (symtab->filename, s->filename) != 0) continue; - if (symtab->fullname != NULL - && symtab_to_fullname (s) != NULL - && FILENAME_CMP (symtab->fullname, s->fullname) != 0) + if (FILENAME_CMP (symtab_to_fullname (symtab), + symtab_to_fullname (s)) != 0) continue; l = LINETABLE (s); ind = find_line_common (l, line, &exact, 0); @@ -2392,8 +2555,7 @@ VEC (CORE_ADDR) * find_pcs_for_symtab_line (struct symtab *symtab, int line, struct linetable_entry **best_item) { - int start = 0, ix; - struct symbol *previous_function = NULL; + int start = 0; VEC (CORE_ADDR) *result = NULL; /* First, collect all the PCs that are at this line. */ @@ -2554,7 +2716,8 @@ find_pc_line_pc_range (CORE_ADDR pc, CORE_ADDR *startptr, CORE_ADDR *endptr) address for that function that has an entry in SYMTAB's line info table. If such an entry cannot be found, return FUNC_ADDR unaltered. */ -CORE_ADDR + +static CORE_ADDR skip_prologue_using_lineinfo (CORE_ADDR func_addr, struct symtab *symtab) { CORE_ADDR func_start, func_end; @@ -2625,6 +2788,7 @@ find_function_start_sal (struct symbol *sym, int funfirstline) If the PC was explicitly specified, the SAL is not changed. If the line number was explicitly specified, at most the SAL's PC is updated. If SAL is already past the prologue, then do nothing. */ + void skip_prologue_sal (struct symtab_and_line *sal) { @@ -2639,7 +2803,7 @@ skip_prologue_sal (struct symtab_and_line *sal) struct block *b, *function_block; int force_skip, skip; - /* Do not change the SAL is PC was specified explicitly. */ + /* Do not change the SAL if PC was specified explicitly. */ if (sal->explicit_pc) return; @@ -2729,7 +2893,7 @@ skip_prologue_sal (struct symtab_and_line *sal) to `__main' in `main' between the prologue and before user code. */ if (gdbarch_skip_main_prologue_p (gdbarch) - && name && strcmp (name, "main") == 0) + && name && strcmp_iw (name, "main") == 0) { pc = gdbarch_skip_main_prologue (gdbarch, pc); /* Recalculate the line number (might not be N+1). */ @@ -2797,6 +2961,7 @@ skip_prologue_sal (struct symtab_and_line *sal) some legitimate operator text, return a pointer to the beginning of the substring of the operator text. Otherwise, return "". */ + static char * operator_chars (char *p, char **end) { @@ -2931,55 +3096,93 @@ operator_chars (char *p, char **end) } -/* If FILE is not already in the table of files, return zero; +/* Cache to watch for file names already seen by filename_seen. */ + +struct filename_seen_cache +{ + /* Table of files seen so far. */ + htab_t tab; + /* Initial size of the table. It automagically grows from here. */ +#define INITIAL_FILENAME_SEEN_CACHE_SIZE 100 +}; + +/* filename_seen_cache constructor. */ + +static struct filename_seen_cache * +create_filename_seen_cache (void) +{ + struct filename_seen_cache *cache; + + cache = XNEW (struct filename_seen_cache); + cache->tab = htab_create_alloc (INITIAL_FILENAME_SEEN_CACHE_SIZE, + filename_hash, filename_eq, + NULL, xcalloc, xfree); + + return cache; +} + +/* Empty the cache, but do not delete it. */ + +static void +clear_filename_seen_cache (struct filename_seen_cache *cache) +{ + htab_empty (cache->tab); +} + +/* filename_seen_cache destructor. + This takes a void * argument as it is generally used as a cleanup. */ + +static void +delete_filename_seen_cache (void *ptr) +{ + struct filename_seen_cache *cache = ptr; + + htab_delete (cache->tab); + xfree (cache); +} + +/* If FILE is not already in the table of files in CACHE, return zero; otherwise return non-zero. Optionally add FILE to the table if ADD - is non-zero. If *FIRST is non-zero, forget the old table - contents. */ + is non-zero. + + NOTE: We don't manage space for FILE, we assume FILE lives as long + as the caller needs. */ + static int -filename_seen (const char *file, int add, int *first) +filename_seen (struct filename_seen_cache *cache, const char *file, int add) { - /* Table of files seen so far. */ - static const char **tab = NULL; - /* Allocated size of tab in elements. - Start with one 256-byte block (when using GNU malloc.c). - 24 is the malloc overhead when range checking is in effect. */ - static int tab_alloc_size = (256 - 24) / sizeof (char *); - /* Current size of tab in elements. */ - static int tab_cur_size; - const char **p; - - if (*first) - { - if (tab == NULL) - tab = (const char **) xmalloc (tab_alloc_size * sizeof (*tab)); - tab_cur_size = 0; - } + void **slot; /* Is FILE in tab? */ - for (p = tab; p < tab + tab_cur_size; p++) - if (filename_cmp (*p, file) == 0) - return 1; + slot = htab_find_slot (cache->tab, file, add ? INSERT : NO_INSERT); + if (*slot != NULL) + return 1; /* No; maybe add it to tab. */ if (add) - { - if (tab_cur_size == tab_alloc_size) - { - tab_alloc_size *= 2; - tab = (const char **) xrealloc ((char *) tab, - tab_alloc_size * sizeof (*tab)); - } - tab[tab_cur_size++] = file; - } + *slot = (char *) file; return 0; } +/* Data structure to maintain printing state for output_source_filename. */ + +struct output_source_filename_data +{ + /* Cache of what we've seen so far. */ + struct filename_seen_cache *filename_seen_cache; + + /* Flag of whether we're printing the first one. */ + int first; +}; + /* Slave routine for sources_info. Force line breaks at ,'s. - NAME is the name to print and *FIRST is nonzero if this is the first - name printed. Set *FIRST to zero. */ + NAME is the name to print. + DATA contains the state for printing and watching for duplicates. */ + static void -output_source_filename (const char *name, int *first) +output_source_filename (const char *name, + struct output_source_filename_data *data) { /* Since a single source file can result in several partial symbol tables, we need to avoid printing it more than once. Note: if @@ -2991,26 +3194,23 @@ output_source_filename (const char *name, int *first) symtabs; it doesn't hurt to check. */ /* Was NAME already seen? */ - if (filename_seen (name, 1, first)) + if (filename_seen (data->filename_seen_cache, name, 1)) { /* Yes; don't print it again. */ return; } + /* No; print it and reset *FIRST. */ - if (*first) - { - *first = 0; - } - else - { - printf_filtered (", "); - } + if (! data->first) + printf_filtered (", "); + data->first = 0; wrap_here (""); fputs_filtered (name, gdb_stdout); } /* A callback for map_partial_symbol_filenames. */ + static void output_partial_symbol_filename (const char *filename, const char *fullname, void *data) @@ -3023,35 +3223,46 @@ sources_info (char *ignore, int from_tty) { struct symtab *s; struct objfile *objfile; - int first; + struct output_source_filename_data data; + struct cleanup *cleanups; if (!have_full_symbols () && !have_partial_symbols ()) { error (_("No symbol table is loaded. Use the \"file\" command.")); } + data.filename_seen_cache = create_filename_seen_cache (); + cleanups = make_cleanup (delete_filename_seen_cache, + data.filename_seen_cache); + printf_filtered ("Source files for which symbols have been read in:\n\n"); - first = 1; + data.first = 1; ALL_SYMTABS (objfile, s) { const char *fullname = symtab_to_fullname (s); - output_source_filename (fullname ? fullname : s->filename, &first); + output_source_filename (fullname, &data); } printf_filtered ("\n\n"); printf_filtered ("Source files for which symbols " "will be read in on demand:\n\n"); - first = 1; - map_partial_symbol_filenames (output_partial_symbol_filename, &first, + clear_filename_seen_cache (data.filename_seen_cache); + data.first = 1; + map_partial_symbol_filenames (output_partial_symbol_filename, &data, 1 /*need_fullname*/); printf_filtered ("\n"); + + do_cleanups (cleanups); } +/* Compare FILE against all the NFILES entries of FILES. If BASENAMES is + non-zero compare only lbasename of FILES. */ + static int -file_matches (const char *file, char *files[], int nfiles) +file_matches (const char *file, char *files[], int nfiles, int basenames) { int i; @@ -3059,7 +3270,9 @@ file_matches (const char *file, char *files[], int nfiles) { for (i = 0; i < nfiles; i++) { - if (filename_cmp (files[i], lbasename (file)) == 0) + if (compare_filenames_for_search (file, (basenames + ? lbasename (files[i]) + : files[i]))) return 1; } } @@ -3069,6 +3282,7 @@ file_matches (const char *file, char *files[], int nfiles) } /* Free any memory associated with a search. */ + void free_search_symbols (struct symbol_search *symbols) { @@ -3096,6 +3310,7 @@ make_cleanup_free_search_symbols (struct symbol_search *symbols) /* Helper function for sort_search_symbols and qsort. Can only sort symbols, not minimal symbols. */ + static int compare_search_syms (const void *sa, const void *sb) { @@ -3109,6 +3324,7 @@ compare_search_syms (const void *sa, const void *sb) /* Sort the ``nfound'' symbols in the list after prevtail. Leave prevtail where it is, but update its next pointer to point to the first of the sorted symbols. */ + static struct symbol_search * sort_search_symbols (struct symbol_search *prevtail, int nfound) { @@ -3154,18 +3370,20 @@ struct search_symbols_data }; /* A callback for expand_symtabs_matching. */ + static int -search_symbols_file_matches (const char *filename, void *user_data) +search_symbols_file_matches (const char *filename, void *user_data, + int basenames) { struct search_symbols_data *data = user_data; - return file_matches (filename, data->files, data->nfiles); + return file_matches (filename, data->files, data->nfiles, basenames); } /* A callback for expand_symtabs_matching. */ + static int -search_symbols_name_matches (const struct language_defn *language, - const char *symname, void *user_data) +search_symbols_name_matches (const char *symname, void *user_data) { struct search_symbols_data *data = user_data; @@ -3196,11 +3414,10 @@ search_symbols (char *regexp, enum search_domain kind, struct blockvector *bv; struct block *b; int i = 0; - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym; struct objfile *objfile; struct minimal_symbol *msymbol; - char *val; int found_misc = 0; static const enum minimal_symbol_type types[] = {mst_data, mst_text, mst_abs}; @@ -3296,7 +3513,9 @@ search_symbols (char *regexp, enum search_domain kind, { if (objfile->sf) objfile->sf->qf->expand_symtabs_matching (objfile, - search_symbols_file_matches, + (nfiles == 0 + ? NULL + : search_symbols_file_matches), search_symbols_name_matches, kind, &datum); @@ -3311,10 +3530,14 @@ search_symbols (char *regexp, enum search_domain kind, The symbol will then be found during the scan of symtabs below. For functions, find_pc_symtab should succeed if we have debug info - for the function, for variables we have to call lookup_symbol - to determine if the variable has debug info. + for the function, for variables we have to call + lookup_symbol_in_objfile_from_linkage_name to determine if the variable + has debug info. If the lookup fails, set found_misc so that we will rescan to print - any matching symbols without debug info. */ + any matching symbols without debug info. + We only search the objfile the msymbol came from, we no longer search + all objfiles. In large programs (1000s of shared libs) searching all + objfiles is not worth the pain. */ if (nfiles == 0 && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN)) { @@ -3322,30 +3545,27 @@ search_symbols (char *regexp, enum search_domain kind, { QUIT; - if (MSYMBOL_TYPE (msymbol) == ourtype || - MSYMBOL_TYPE (msymbol) == ourtype2 || - MSYMBOL_TYPE (msymbol) == ourtype3 || - MSYMBOL_TYPE (msymbol) == ourtype4) + if (msymbol->created_by_gdb) + continue; + + if (MSYMBOL_TYPE (msymbol) == ourtype + || MSYMBOL_TYPE (msymbol) == ourtype2 + || MSYMBOL_TYPE (msymbol) == ourtype3 + || MSYMBOL_TYPE (msymbol) == ourtype4) { if (!datum.preg_p || regexec (&datum.preg, SYMBOL_NATURAL_NAME (msymbol), 0, NULL, 0) == 0) { - if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol))) - { - /* FIXME: carlton/2003-02-04: Given that the - semantics of lookup_symbol keeps on changing - slightly, it would be a nice idea if we had a - function lookup_symbol_minsym that found the - symbol associated to a given minimal symbol (if - any). */ - if (kind == FUNCTIONS_DOMAIN - || lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol), - (struct block *) NULL, - VAR_DOMAIN, 0) - == NULL) - found_misc = 1; - } + /* Note: An important side-effect of these lookup functions + is to expand the symbol table if msymbol is found, for the + benefit of the next loop on ALL_PRIMARY_SYMTABS. */ + if (kind == FUNCTIONS_DOMAIN + ? find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)) == NULL + : (lookup_symbol_in_objfile_from_linkage_name + (objfile, SYMBOL_LINKAGE_NAME (msymbol), VAR_DOMAIN) + == NULL)) + found_misc = 1; } } } @@ -3354,97 +3574,107 @@ search_symbols (char *regexp, enum search_domain kind, ALL_PRIMARY_SYMTABS (objfile, s) { bv = BLOCKVECTOR (s); - for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) - { - struct symbol_search *prevtail = tail; - int nfound = 0; + for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) + { + struct symbol_search *prevtail = tail; + int nfound = 0; - b = BLOCKVECTOR_BLOCK (bv, i); - ALL_BLOCK_SYMBOLS (b, iter, sym) - { - struct symtab *real_symtab = SYMBOL_SYMTAB (sym); - - QUIT; - - if (file_matches (real_symtab->filename, files, nfiles) - && ((!datum.preg_p - || regexec (&datum.preg, SYMBOL_NATURAL_NAME (sym), 0, - NULL, 0) == 0) - && ((kind == VARIABLES_DOMAIN - && SYMBOL_CLASS (sym) != LOC_TYPEDEF - && SYMBOL_CLASS (sym) != LOC_UNRESOLVED - && SYMBOL_CLASS (sym) != LOC_BLOCK - /* LOC_CONST can be used for more than just enums, - e.g., c++ static const members. - We only want to skip enums here. */ - && !(SYMBOL_CLASS (sym) == LOC_CONST - && TYPE_CODE (SYMBOL_TYPE (sym)) - == TYPE_CODE_ENUM)) - || (kind == FUNCTIONS_DOMAIN - && SYMBOL_CLASS (sym) == LOC_BLOCK) - || (kind == TYPES_DOMAIN - && SYMBOL_CLASS (sym) == LOC_TYPEDEF)))) - { - /* match */ - psr = (struct symbol_search *) - xmalloc (sizeof (struct symbol_search)); - psr->block = i; - psr->symtab = real_symtab; - psr->symbol = sym; - psr->msymbol = NULL; - psr->next = NULL; - if (tail == NULL) - sr = psr; - else - tail->next = psr; - tail = psr; - nfound ++; - } - } - if (nfound > 0) - { - if (prevtail == NULL) - { - struct symbol_search dummy; + b = BLOCKVECTOR_BLOCK (bv, i); + ALL_BLOCK_SYMBOLS (b, iter, sym) + { + struct symtab *real_symtab = SYMBOL_SYMTAB (sym); + + QUIT; + + /* Check first sole REAL_SYMTAB->FILENAME. It does not need to be + a substring of symtab_to_fullname as it may contain "./" etc. */ + if ((file_matches (real_symtab->filename, files, nfiles, 0) + || ((basenames_may_differ + || file_matches (lbasename (real_symtab->filename), + files, nfiles, 1)) + && file_matches (symtab_to_fullname (real_symtab), + files, nfiles, 0))) + && ((!datum.preg_p + || regexec (&datum.preg, SYMBOL_NATURAL_NAME (sym), 0, + NULL, 0) == 0) + && ((kind == VARIABLES_DOMAIN + && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_UNRESOLVED + && SYMBOL_CLASS (sym) != LOC_BLOCK + /* LOC_CONST can be used for more than just enums, + e.g., c++ static const members. + We only want to skip enums here. */ + && !(SYMBOL_CLASS (sym) == LOC_CONST + && TYPE_CODE (SYMBOL_TYPE (sym)) + == TYPE_CODE_ENUM)) + || (kind == FUNCTIONS_DOMAIN + && SYMBOL_CLASS (sym) == LOC_BLOCK) + || (kind == TYPES_DOMAIN + && SYMBOL_CLASS (sym) == LOC_TYPEDEF)))) + { + /* match */ + psr = (struct symbol_search *) + xmalloc (sizeof (struct symbol_search)); + psr->block = i; + psr->symtab = real_symtab; + psr->symbol = sym; + psr->msymbol = NULL; + psr->next = NULL; + if (tail == NULL) + sr = psr; + else + tail->next = psr; + tail = psr; + nfound ++; + } + } + if (nfound > 0) + { + if (prevtail == NULL) + { + struct symbol_search dummy; - dummy.next = sr; - tail = sort_search_symbols (&dummy, nfound); - sr = dummy.next; + dummy.next = sr; + tail = sort_search_symbols (&dummy, nfound); + sr = dummy.next; - make_cleanup_free_search_symbols (sr); - } - else - tail = sort_search_symbols (prevtail, nfound); - } - } + make_cleanup_free_search_symbols (sr); + } + else + tail = sort_search_symbols (prevtail, nfound); + } + } } /* If there are no eyes, avoid all contact. I mean, if there are no debug symbols, then print directly from the msymbol_vector. */ - if (found_misc || kind != FUNCTIONS_DOMAIN) + if (found_misc || (nfiles == 0 && kind != FUNCTIONS_DOMAIN)) { ALL_MSYMBOLS (objfile, msymbol) { QUIT; - if (MSYMBOL_TYPE (msymbol) == ourtype || - MSYMBOL_TYPE (msymbol) == ourtype2 || - MSYMBOL_TYPE (msymbol) == ourtype3 || - MSYMBOL_TYPE (msymbol) == ourtype4) + if (msymbol->created_by_gdb) + continue; + + if (MSYMBOL_TYPE (msymbol) == ourtype + || MSYMBOL_TYPE (msymbol) == ourtype2 + || MSYMBOL_TYPE (msymbol) == ourtype3 + || MSYMBOL_TYPE (msymbol) == ourtype4) { if (!datum.preg_p || regexec (&datum.preg, SYMBOL_NATURAL_NAME (msymbol), 0, NULL, 0) == 0) { - /* Functions: Look up by address. */ - if (kind != FUNCTIONS_DOMAIN || - (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))) + /* For functions we can do a quick check of whether the + symbol might be found via find_pc_symtab. */ + if (kind != FUNCTIONS_DOMAIN + || find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)) == NULL) { - /* Variables/Absolutes: Look up by name. */ - if (lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol), - (struct block *) NULL, VAR_DOMAIN, 0) - == NULL) + if (lookup_symbol_in_objfile_from_linkage_name + (objfile, SYMBOL_LINKAGE_NAME (msymbol), VAR_DOMAIN) + == NULL) { /* match */ psr = (struct symbol_search *) @@ -3481,12 +3711,14 @@ search_symbols (char *regexp, enum search_domain kind, static void print_symbol_info (enum search_domain kind, struct symtab *s, struct symbol *sym, - int block, char *last) + int block, const char *last) { - if (last == NULL || filename_cmp (last, s->filename) != 0) + const char *s_filename = symtab_to_filename_for_display (s); + + if (last == NULL || filename_cmp (last, s_filename) != 0) { fputs_filtered ("\nFile ", gdb_stdout); - fputs_filtered (s->filename, gdb_stdout); + fputs_filtered (s_filename, gdb_stdout); fputs_filtered (":\n", gdb_stdout); } @@ -3498,9 +3730,9 @@ print_symbol_info (enum search_domain kind, && SYMBOL_DOMAIN (sym) != STRUCT_DOMAIN) typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout); /* variable, func, or typedef-that-is-c++-class. */ - else if (kind < TYPES_DOMAIN || - (kind == TYPES_DOMAIN && - SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)) + else if (kind < TYPES_DOMAIN + || (kind == TYPES_DOMAIN + && SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)) { type_print (SYMBOL_TYPE (sym), (SYMBOL_CLASS (sym) == LOC_TYPEDEF @@ -3544,7 +3776,7 @@ symtab_symbol_info (char *regexp, enum search_domain kind, int from_tty) struct symbol_search *symbols; struct symbol_search *p; struct cleanup *old_chain; - char *last_filename = NULL; + const char *last_filename = NULL; int first = 1; gdb_assert (kind <= TYPES_DOMAIN); @@ -3553,10 +3785,11 @@ symtab_symbol_info (char *regexp, enum search_domain kind, int from_tty) search_symbols (regexp, kind, 0, (char **) NULL, &symbols); old_chain = make_cleanup_free_search_symbols (symbols); - printf_filtered (regexp - ? "All %ss matching regular expression \"%s\":\n" - : "All defined %ss:\n", - classnames[kind], regexp); + if (regexp != NULL) + printf_filtered (_("All %ss matching regular expression \"%s\":\n"), + classnames[kind], regexp); + else + printf_filtered (_("All defined %ss:\n"), classnames[kind]); for (p = symbols; p != NULL; p = p->next) { @@ -3566,7 +3799,7 @@ symtab_symbol_info (char *regexp, enum search_domain kind, int from_tty) { if (first) { - printf_filtered ("\nNon-debugging symbols:\n"); + printf_filtered (_("\nNon-debugging symbols:\n")); first = 0; } print_msymbol_info (p->msymbol); @@ -3578,7 +3811,7 @@ symtab_symbol_info (char *regexp, enum search_domain kind, int from_tty) p->symbol, p->block, last_filename); - last_filename = p->symtab->filename; + last_filename = symtab_to_filename_for_display (p->symtab); } } @@ -3647,8 +3880,7 @@ rbreak_command (char *regexp, int from_tty) file_name[colon_index--] = 0; files = &file_name; nfiles = 1; - regexp = colon + 1; - while (isspace (*regexp)) regexp++; + regexp = skip_spaces (colon + 1); } } @@ -3662,7 +3894,9 @@ rbreak_command (char *regexp, int from_tty) { if (p->msymbol == NULL) { - int newlen = (strlen (p->symtab->filename) + const char *fullname = symtab_to_fullname (p->symtab); + + int newlen = (strlen (fullname) + strlen (SYMBOL_LINKAGE_NAME (p->symbol)) + 4); @@ -3671,7 +3905,7 @@ rbreak_command (char *regexp, int from_tty) string = xrealloc (string, newlen); len = newlen; } - strcpy (string, p->symtab->filename); + strcpy (string, fullname); strcat (string, ":'"); strcat (string, SYMBOL_LINKAGE_NAME (p->symbol)); strcat (string, "'"); @@ -3680,7 +3914,7 @@ rbreak_command (char *regexp, int from_tty) p->symtab, p->symbol, p->block, - p->symtab->filename); + symtab_to_filename_for_display (p->symtab)); } else { @@ -3742,17 +3976,14 @@ compare_symbol_name (const char *name, const char *sym_text, int sym_text_len) /* Free any memory associated with a completion list. */ static void -free_completion_list (char ***list_ptr) +free_completion_list (VEC (char_ptr) **list_ptr) { - int i = 0; - char **list = *list_ptr; + int i; + char *p; - while (list[i] != NULL) - { - xfree (list[i]); - i++; - } - xfree (list); + for (i = 0; VEC_iterate (char_ptr, *list_ptr, i, p); ++i) + xfree (p); + VEC_free (char_ptr, *list_ptr); } /* Callback for make_cleanup. */ @@ -3765,9 +3996,7 @@ do_free_completion_list (void *list) /* Helper routine for make_symbol_completion_list. */ -static int return_val_size; -static int return_val_index; -static char **return_val; +static VEC (char_ptr) *return_val; #define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \ completion_list_add_name \ @@ -3778,11 +4007,10 @@ static char **return_val; characters. If so, add it to the current completion list. */ static void -completion_list_add_name (char *symname, char *sym_text, int sym_text_len, - char *text, char *word) +completion_list_add_name (const char *symname, + const char *sym_text, int sym_text_len, + const char *text, const char *word) { - int newsize; - /* Clip symbols that cannot match. */ if (!compare_symbol_name (symname, sym_text, sym_text_len)) return; @@ -3813,13 +4041,7 @@ completion_list_add_name (char *symname, char *sym_text, int sym_text_len, strcat (new, symname); } - if (return_val_index + 3 > return_val_size) - { - newsize = (return_val_size *= 2) * sizeof (char *); - return_val = (char **) xrealloc ((char *) return_val, newsize); - } - return_val[return_val_index++] = new; - return_val[return_val_index] = NULL; + VEC_safe_push (char_ptr, return_val, new); } } @@ -3827,13 +4049,14 @@ completion_list_add_name (char *symname, char *sym_text, int sym_text_len, again and feed all the selectors into the mill. */ static void -completion_list_objc_symbol (struct minimal_symbol *msymbol, char *sym_text, - int sym_text_len, char *text, char *word) +completion_list_objc_symbol (struct minimal_symbol *msymbol, + const char *sym_text, int sym_text_len, + const char *text, const char *word) { static char *tmp = NULL; static unsigned int tmplen = 0; - char *method, *category, *selector; + const char *method, *category, *selector; char *tmp2 = NULL; method = SYMBOL_NATURAL_NAME (msymbol); @@ -3959,6 +4182,7 @@ struct add_name_data /* A callback used with macro_for_each and macro_for_each_in_scope. This adds a macro's name to the current completion list. */ + static void add_macro_name (const char *name, const struct macro_definition *ignore, struct macro_source_file *ignore2, int ignore3, @@ -3972,18 +4196,19 @@ add_macro_name (const char *name, const struct macro_definition *ignore, } /* A callback for expand_partial_symbol_names. */ + static int -expand_partial_symbol_name (const struct language_defn *language, - const char *name, void *user_data) +expand_partial_symbol_name (const char *name, void *user_data) { struct add_name_data *datum = (struct add_name_data *) user_data; return compare_symbol_name (name, datum->sym_text, datum->sym_text_len); } -char ** +VEC (char_ptr) * default_make_symbol_completion_list_break_on (char *text, char *word, - const char *break_on) + const char *break_on, + enum type_code code) { /* Problem: All of the symbols have to be copied because readline frees them. I'm not going to worry about this; hopefully there @@ -3995,7 +4220,7 @@ default_make_symbol_completion_list_break_on (char *text, char *word, struct objfile *objfile; struct block *b; const struct block *surrounding_static_block, *surrounding_global_block; - struct dict_iterator iter; + struct block_iterator iter; /* The symbol we are completing on. Points in same buffer as text. */ char *sym_text; /* Length of sym_text. */ @@ -4036,9 +4261,7 @@ default_make_symbol_completion_list_break_on (char *text, char *word, /* A double-quoted string is never a symbol, nor does it make sense to complete it any other way. */ { - return_val = (char **) xmalloc (sizeof (char *)); - return_val[0] = NULL; - return return_val; + return NULL; } else { @@ -4074,10 +4297,7 @@ default_make_symbol_completion_list_break_on (char *text, char *word, } gdb_assert (sym_text[sym_text_len] == '\0' || sym_text[sym_text_len] == '('); - return_val_size = 100; - return_val_index = 0; - return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *)); - return_val[0] = NULL; + return_val = NULL; back_to = make_cleanup (do_free_completion_list, &return_val); datum.sym_text = sym_text; @@ -4095,13 +4315,18 @@ default_make_symbol_completion_list_break_on (char *text, char *word, anything that isn't a text symbol (everything else will be handled by the psymtab code above). */ - ALL_MSYMBOLS (objfile, msymbol) - { - QUIT; - COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, word); + if (code == TYPE_CODE_UNDEF) + { + ALL_MSYMBOLS (objfile, msymbol) + { + QUIT; + COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, + word); - completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text, word); - } + completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text, + word); + } + } /* Search upwards from currently selected frame (so that we can complete on local vars). Also catch fields of types defined in @@ -4118,10 +4343,17 @@ default_make_symbol_completion_list_break_on (char *text, char *word, 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); + if (code == TYPE_CODE_UNDEF) + { + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, + word); + completion_list_add_fields (sym, sym_text, sym_text_len, text, + word); + } + else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN + && TYPE_CODE (SYMBOL_TYPE (sym)) == code) + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, + word); } /* Stop when we encounter an enclosing function. Do not stop for @@ -4134,13 +4366,16 @@ default_make_symbol_completion_list_break_on (char *text, char *word, /* Add fields from the file's types; symbols will be added below. */ - 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 (code == TYPE_CODE_UNDEF) + { + 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); + 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. */ @@ -4151,7 +4386,10 @@ default_make_symbol_completion_list_break_on (char *text, char *word, b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); ALL_BLOCK_SYMBOLS (b, iter, sym) { - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + if (code == TYPE_CODE_UNDEF + || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN + && TYPE_CODE (SYMBOL_TYPE (sym)) == code)) + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); } } @@ -4161,11 +4399,17 @@ default_make_symbol_completion_list_break_on (char *text, char *word, b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); ALL_BLOCK_SYMBOLS (b, iter, sym) { - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + if (code == TYPE_CODE_UNDEF + || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN + && TYPE_CODE (SYMBOL_TYPE (sym)) == code)) + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); } } - if (current_language->la_macro_expansion == macro_expansion_c) + /* Skip macros if we are completing a struct tag -- arguable but + usually what is expected. */ + if (current_language->la_macro_expansion == macro_expansion_c + && code == TYPE_CODE_UNDEF) { struct macro_scope *scope; @@ -4192,26 +4436,41 @@ default_make_symbol_completion_list_break_on (char *text, char *word, return (return_val); } -char ** -default_make_symbol_completion_list (char *text, char *word) +VEC (char_ptr) * +default_make_symbol_completion_list (char *text, char *word, + enum type_code code) { - return default_make_symbol_completion_list_break_on (text, word, ""); + return default_make_symbol_completion_list_break_on (text, word, "", code); } -/* Return a NULL terminated array of all symbols (regardless of class) - which begin by matching TEXT. If the answer is no symbols, then - the return value is an array which contains only a NULL pointer. */ +/* Return a vector of all symbols (regardless of class) which begin by + matching TEXT. If the answer is no symbols, then the return value + is NULL. */ -char ** +VEC (char_ptr) * make_symbol_completion_list (char *text, char *word) { - return current_language->la_make_symbol_completion_list (text, word); + return current_language->la_make_symbol_completion_list (text, word, + TYPE_CODE_UNDEF); +} + +/* Like make_symbol_completion_list, but only return STRUCT_DOMAIN + symbols whose type code is CODE. */ + +VEC (char_ptr) * +make_symbol_completion_type (char *text, char *word, enum type_code code) +{ + gdb_assert (code == TYPE_CODE_UNION + || code == TYPE_CODE_STRUCT + || code == TYPE_CODE_CLASS + || code == TYPE_CODE_ENUM); + return current_language->la_make_symbol_completion_list (text, word, code); } /* Like make_symbol_completion_list, but suitable for use as a completion function. */ -char ** +VEC (char_ptr) * make_symbol_completion_list_fn (struct cmd_list_element *ignore, char *text, char *word) { @@ -4221,13 +4480,13 @@ make_symbol_completion_list_fn (struct cmd_list_element *ignore, /* Like make_symbol_completion_list, but returns a list of symbols defined in a source file FILE. */ -char ** +VEC (char_ptr) * make_file_symbol_completion_list (char *text, char *word, char *srcfile) { struct symbol *sym; struct symtab *s; struct block *b; - struct dict_iterator iter; + struct block_iterator iter; /* The symbol we are completing on. Points in same buffer as text. */ char *sym_text; /* Length of sym_text. */ @@ -4267,9 +4526,7 @@ make_file_symbol_completion_list (char *text, char *word, char *srcfile) /* A double-quoted string is never a symbol, nor does it make sense to complete it any other way. */ { - return_val = (char **) xmalloc (sizeof (char *)); - return_val[0] = NULL; - return return_val; + return NULL; } else { @@ -4280,10 +4537,7 @@ make_file_symbol_completion_list (char *text, char *word, char *srcfile) sym_text_len = strlen (sym_text); - return_val_size = 10; - return_val_index = 0; - return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *)); - return_val[0] = NULL; + return_val = NULL; /* Find the symtab for SRCFILE (this loads it if it was not yet read in). */ @@ -4326,18 +4580,11 @@ make_file_symbol_completion_list (char *text, char *word, char *srcfile) static void add_filename_to_list (const char *fname, char *text, char *word, - char ***list, int *list_used, int *list_alloced) + VEC (char_ptr) **list) { char *new; size_t fnlen = strlen (fname); - if (*list_used + 1 >= *list_alloced) - { - *list_alloced *= 2; - *list = (char **) xrealloc ((char *) *list, - *list_alloced * sizeof (char *)); - } - if (word == text) { /* Return exactly fname. */ @@ -4358,8 +4605,7 @@ add_filename_to_list (const char *fname, char *text, char *word, new[text - word] = '\0'; strcat (new, fname); } - (*list)[*list_used] = new; - (*list)[++*list_used] = NULL; + VEC_safe_push (char_ptr, *list, new); } static int @@ -4383,16 +4629,15 @@ not_interesting_fname (const char *fname) map_partial_symbol_filenames. */ struct add_partial_filename_data { - int *first; + struct filename_seen_cache *filename_seen_cache; char *text; char *word; int text_len; - char ***list; - int *list_used; - int *list_alloced; + VEC (char_ptr) **list; }; /* A callback for map_partial_symbol_filenames. */ + static void maybe_add_partial_symtab_filename (const char *filename, const char *fullname, void *user_data) @@ -4401,63 +4646,60 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname, if (not_interesting_fname (filename)) return; - if (!filename_seen (filename, 1, data->first) + if (!filename_seen (data->filename_seen_cache, filename, 1) && filename_ncmp (filename, data->text, data->text_len) == 0) { /* This file matches for a completion; add it to the current list of matches. */ - add_filename_to_list (filename, data->text, data->word, - data->list, data->list_used, data->list_alloced); + add_filename_to_list (filename, data->text, data->word, data->list); } else { const char *base_name = lbasename (filename); if (base_name != filename - && !filename_seen (base_name, 1, data->first) + && !filename_seen (data->filename_seen_cache, base_name, 1) && filename_ncmp (base_name, data->text, data->text_len) == 0) - add_filename_to_list (base_name, data->text, data->word, - data->list, data->list_used, data->list_alloced); + add_filename_to_list (base_name, data->text, data->word, data->list); } } -/* Return a NULL terminated array of all source files whose names - begin with matching TEXT. The file names are looked up in the - symbol tables of this program. If the answer is no matchess, then - the return value is an array which contains only a NULL pointer. */ +/* Return a vector of all source files whose names begin with matching + TEXT. The file names are looked up in the symbol tables of this + program. If the answer is no matchess, then the return value is + NULL. */ -char ** +VEC (char_ptr) * make_source_files_completion_list (char *text, char *word) { struct symtab *s; struct objfile *objfile; - int first = 1; - int list_alloced = 1; - int list_used = 0; size_t text_len = strlen (text); - char **list = (char **) xmalloc (list_alloced * sizeof (char *)); + VEC (char_ptr) *list = NULL; const char *base_name; struct add_partial_filename_data datum; - struct cleanup *back_to; - - list[0] = NULL; + struct filename_seen_cache *filename_seen_cache; + struct cleanup *back_to, *cache_cleanup; if (!have_full_symbols () && !have_partial_symbols ()) return list; back_to = make_cleanup (do_free_completion_list, &list); + filename_seen_cache = create_filename_seen_cache (); + cache_cleanup = make_cleanup (delete_filename_seen_cache, + filename_seen_cache); + ALL_SYMTABS (objfile, s) { if (not_interesting_fname (s->filename)) continue; - if (!filename_seen (s->filename, 1, &first) + if (!filename_seen (filename_seen_cache, s->filename, 1) && filename_ncmp (s->filename, text, text_len) == 0) { /* This file matches for a completion; add it to the current list of matches. */ - add_filename_to_list (s->filename, text, word, - &list, &list_used, &list_alloced); + add_filename_to_list (s->filename, text, word, &list); } else { @@ -4467,22 +4709,21 @@ make_source_files_completion_list (char *text, char *word) command do when they parse file names. */ base_name = lbasename (s->filename); if (base_name != s->filename - && !filename_seen (base_name, 1, &first) + && !filename_seen (filename_seen_cache, base_name, 1) && filename_ncmp (base_name, text, text_len) == 0) - add_filename_to_list (base_name, text, word, - &list, &list_used, &list_alloced); + add_filename_to_list (base_name, text, word, &list); } } - datum.first = &first; + datum.filename_seen_cache = filename_seen_cache; datum.text = text; datum.word = word; datum.text_len = text_len; datum.list = &list; - datum.list_used = &list_used; - datum.list_alloced = &list_alloced; map_partial_symbol_filenames (maybe_add_partial_symtab_filename, &datum, 0 /*need_fullname*/); + + do_cleanups (cache_cleanup); discard_cleanups (back_to); return list; @@ -4632,6 +4873,10 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr) line mark the prologue -> body transition. */ if (sal.line >= prologue_sal.line) break; + /* Likewise if we are in a different symtab altogether + (e.g. within a file included via #include).  */ + if (sal.symtab != prologue_sal.symtab) + break; /* The line number is smaller. Check that it's from the same function, not something inlined. If it's inlined, @@ -4671,27 +4916,6 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr) return prologue_sal.pc; } -struct symtabs_and_lines -decode_line_spec (char *string, int flags) -{ - struct symtabs_and_lines sals; - struct symtab_and_line cursal; - - if (string == 0) - error (_("Empty line specification.")); - - /* We use whatever is set as the current source line. We do not try - and get a default or it will recursively call us! */ - cursal = get_current_source_symtab_and_line (); - - sals = decode_line_1 (&string, flags, - cursal.symtab, cursal.line); - - if (*string) - error (_("Junk at end of line specification: %s"), string); - return sals; -} - /* Track MAIN */ static char *name_of_main; enum language language_of_main = language_unknown; @@ -4743,6 +4967,13 @@ find_main_name (void) return; } + new_main_name = go_main_name (); + if (new_main_name != NULL) + { + set_main_name (new_main_name); + return; + } + new_main_name = pascal_main_name (); if (new_main_name != NULL) { @@ -4859,5 +5090,13 @@ one base name, and gdb will do file name comparisons more efficiently."), NULL, NULL, &setlist, &showlist); + add_setshow_boolean_cmd ("symtab-create", no_class, &symtab_create_debug, + _("Set debugging of symbol table creation."), + _("Show debugging of symbol table creation."), _("\ +When enabled, debugging messages are printed when building symbol tables."), + NULL, + NULL, + &setdebuglist, &showdebuglist); + observer_attach_executable_changed (symtab_observer_executable_changed); } diff --git a/contrib/gdb-7/gdb/symtab.h b/contrib/gdb-7/gdb/symtab.h index 9a26656acd..378e9332cd 100644 --- a/contrib/gdb-7/gdb/symtab.h +++ b/contrib/gdb-7/gdb/symtab.h @@ -1,7 +1,6 @@ /* Symbol table definitions for GDB. - Copyright (C) 1986, 1988-2004, 2007-2012 Free Software Foundation, - Inc. + Copyright (C) 1986-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +21,8 @@ #define SYMTAB_H 1 #include "vec.h" +#include "gdb_vecs.h" +#include "gdbtypes.h" /* Opaque declarations. */ struct ui_file; @@ -35,6 +36,8 @@ struct axs_value; struct agent_expr; struct program_space; struct language_defn; +struct probe; +struct common_block; /* Some of the structures in this file are space critical. The space-critical structures are: @@ -81,7 +84,7 @@ struct language_defn; struct cplus_specific { - char *demangled_name; + const char *demangled_name; }; /* Define a structure for the information that is common to all symbol types, @@ -99,7 +102,7 @@ struct general_symbol_info the mangled name and demangled name, this is the mangled name. */ - char *name; + const char *name; /* Value of the symbol. Which member of this union to use, and what it means, depends on what kind of symbol this is and its @@ -109,10 +112,7 @@ struct general_symbol_info union { - /* The fact that this is a long not a LONGEST mainly limits the - range of a LOC_CONST. Since LOC_CONST_BYTES exists, I'm not - sure that is a big deal. */ - long ivalue; + LONGEST ivalue; struct block *block; @@ -120,6 +120,10 @@ struct general_symbol_info CORE_ADDR address; + /* A common block. Used with LOC_COMMON_BLOCK. */ + + struct common_block *common_block; + /* For opaque typedef struct chain. */ struct symbol *chain; @@ -135,7 +139,7 @@ struct general_symbol_info currently used by Ada, Java, and Objective C. */ struct mangled_lang { - char *demangled_name; + const char *demangled_name; } mangled_lang; @@ -163,10 +167,12 @@ struct general_symbol_info struct obj_section *obj_section; }; -extern void symbol_set_demangled_name (struct general_symbol_info *, char *, +extern void symbol_set_demangled_name (struct general_symbol_info *, + const char *, struct objfile *); -extern char *symbol_get_demangled_name (const struct general_symbol_info *); +extern const char *symbol_get_demangled_name + (const struct general_symbol_info *); extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *); @@ -181,6 +187,7 @@ extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *); #define SYMBOL_VALUE(symbol) (symbol)->ginfo.value.ivalue #define SYMBOL_VALUE_ADDRESS(symbol) (symbol)->ginfo.value.address #define SYMBOL_VALUE_BYTES(symbol) (symbol)->ginfo.value.bytes +#define SYMBOL_VALUE_COMMON_BLOCK(symbol) (symbol)->ginfo.value.common_block #define SYMBOL_BLOCK_VALUE(symbol) (symbol)->ginfo.value.block #define SYMBOL_VALUE_CHAIN(symbol) (symbol)->ginfo.value.chain #define SYMBOL_LANGUAGE(symbol) (symbol)->ginfo.language @@ -225,7 +232,8 @@ extern void symbol_set_names (struct general_symbol_info *symbol, #define SYMBOL_NATURAL_NAME(symbol) \ (symbol_natural_name (&(symbol)->ginfo)) -extern char *symbol_natural_name (const struct general_symbol_info *symbol); +extern const char *symbol_natural_name + (const struct general_symbol_info *symbol); /* Return SYMBOL's name from the point of view of the linker. In languages like C++ where symbols may be mangled for ease of @@ -238,7 +246,8 @@ extern char *symbol_natural_name (const struct general_symbol_info *symbol); that symbol. If no demangled name exists, return NULL. */ #define SYMBOL_DEMANGLED_NAME(symbol) \ (symbol_demangled_name (&(symbol)->ginfo)) -extern char *symbol_demangled_name (const struct general_symbol_info *symbol); +extern const char *symbol_demangled_name + (const struct general_symbol_info *symbol); /* Macro that returns a version of the name of a symbol that is suitable for output. In C++ this is the "demangled" form of the @@ -254,21 +263,6 @@ extern char *symbol_demangled_name (const struct general_symbol_info *symbol); (demangle ? SYMBOL_NATURAL_NAME (symbol) : SYMBOL_LINKAGE_NAME (symbol)) extern int demangle; -/* Macro that tests a symbol for a match against a specified name string. - First test the unencoded name, then looks for and test a C++ encoded - name if it exists. Note that whitespace is ignored while attempting to - match a C++ encoded name, so that "foo::bar(int,long)" is the same as - "foo :: bar (int, long)". - Evaluates to zero if the match fails, or nonzero if it succeeds. */ - -/* Macro that tests a symbol for a match against a specified name - string. It tests against SYMBOL_NATURAL_NAME, and it ignores - whitespace and trailing parentheses. (See strcmp_iw for details - about its behavior.) */ - -#define SYMBOL_MATCHES_NATURAL_NAME(symbol, name) \ - (strcmp_iw (SYMBOL_NATURAL_NAME (symbol), (name)) == 0) - /* Macro that returns the name to be used when sorting and searching symbols. In C++, Chill, and Java, we search for the demangled form of a name, and so sort symbols accordingly. In Ada, however, we search by mangled @@ -276,10 +270,11 @@ extern int demangle; returns the same value (same pointer) as SYMBOL_LINKAGE_NAME. */ #define SYMBOL_SEARCH_NAME(symbol) \ (symbol_search_name (&(symbol)->ginfo)) -extern char *symbol_search_name (const struct general_symbol_info *); +extern const char *symbol_search_name (const struct general_symbol_info *); -/* Analogous to SYMBOL_MATCHES_NATURAL_NAME, but uses the search - name. */ +/* Return non-zero if NAME matches the "search" name of SYMBOL. + Whitespace and trailing parentheses are ignored. + See strcmp_iw for details about its behavior. */ #define SYMBOL_MATCHES_SEARCH_NAME(symbol, name) \ (strcmp_iw (SYMBOL_SEARCH_NAME (symbol), (name)) == 0) @@ -346,16 +341,25 @@ struct minimal_symbol unsigned long size; /* Which source file is this symbol in? Only relevant for mst_file_*. */ - char *filename; + const char *filename; /* Classification type for this minimal symbol. */ ENUM_BITFIELD(minimal_symbol_type) type : 8; + /* Non-zero if this symbol was created by gdb. + Such symbols do not appear in the output of "info var|fun". */ + unsigned int created_by_gdb : 1; + /* Two flag bits provided for the use of the target. */ unsigned int target_flag_1 : 1; unsigned int target_flag_2 : 1; + /* Nonzero iff the size of the minimal symbol has been set. + Symbol size information can sometimes not be determined, because + the object file format may not carry that piece of information. */ + unsigned int has_size : 1; + /* Minimal symbols with the same hash key are kept on a linked list. This is the link. */ @@ -369,9 +373,18 @@ struct minimal_symbol #define MSYMBOL_TARGET_FLAG_1(msymbol) (msymbol)->target_flag_1 #define MSYMBOL_TARGET_FLAG_2(msymbol) (msymbol)->target_flag_2 -#define MSYMBOL_SIZE(msymbol) (msymbol)->size +#define MSYMBOL_SIZE(msymbol) ((msymbol)->size + 0) +#define SET_MSYMBOL_SIZE(msymbol, sz) \ + do \ + { \ + (msymbol)->size = sz; \ + (msymbol)->has_size = 1; \ + } while (0) +#define MSYMBOL_HAS_SIZE(msymbol) ((msymbol)->has_size + 0) #define MSYMBOL_TYPE(msymbol) (msymbol)->type +#include "minsyms.h" + /* Represent one symbol name; a variable, constant, function or typedef. */ @@ -400,7 +413,11 @@ typedef enum domain_enum_tag /* LABEL_DOMAIN may be used for names of labels (for gotos). */ - LABEL_DOMAIN + LABEL_DOMAIN, + + /* Fortran common blocks. Their naming must be separate from VAR_DOMAIN. + They also always use LOC_COMMON_BLOCK. */ + COMMON_BLOCK_DOMAIN } domain_enum; /* Searching domains, used for `search_symbols'. Element numbers are @@ -518,6 +535,10 @@ enum address_class /* The variable's address is computed by a set of location functions (see "struct symbol_computed_ops" below). */ LOC_COMPUTED, + + /* The variable uses general_symbol_info->value->common_block field. + It also always uses COMMON_BLOCK_DOMAIN. */ + LOC_COMMON_BLOCK, }; /* The methods needed to implement LOC_COMPUTED. These methods can @@ -799,7 +820,7 @@ struct symtab all the symtabs in a given compilation unit. */ struct macro_table *macro_table; - /* Name of this source file. */ + /* Name of this source file. This pointer is never NULL. */ char *filename; @@ -844,6 +865,23 @@ struct symtab /* struct call_site entries for this compilation unit or NULL. */ htab_t call_site_htab; + + /* If non-NULL, then this points to a NULL-terminated vector of + included symbol tables. When searching the static or global + block of this symbol table, the corresponding block of all + included symbol tables will also be searched. Note that this + list must be flattened -- the symbol reader is responsible for + ensuring that this vector contains the transitive closure of all + included symbol tables. */ + + struct symtab **includes; + + /* If this is an included symbol table, this points to one includer + of the table. This user is considered the canonical symbol table + containing this one. An included symbol table may itself be + included by another. */ + + struct symtab *user; }; #define BLOCKVECTOR(symtab) (symtab)->blockvector @@ -886,19 +924,42 @@ int symbol_matches_domain (enum language symbol_language, extern struct symtab *lookup_symtab (const char *); +/* An object of this type is passed as the 'is_a_field_of_this' + argument to lookup_symbol and lookup_symbol_in_language. */ + +struct field_of_this_result +{ + /* The type in which the field was found. If this is NULL then the + symbol was not found in 'this'. If non-NULL, then one of the + other fields will be non-NULL as well. */ + + struct type *type; + + /* If the symbol was found as an ordinary field of 'this', then this + is non-NULL and points to the particular field. */ + + struct field *field; + + /* If the symbol was found as an function field of 'this', then this + is non-NULL and points to the particular field. */ + + struct fn_fieldlist *fn_field; +}; + /* lookup a symbol by name (optional block) in language. */ extern struct symbol *lookup_symbol_in_language (const char *, const struct block *, const domain_enum, enum language, - int *); + struct field_of_this_result *); /* lookup a symbol by name (optional block, optional symtab) in the current language. */ extern struct symbol *lookup_symbol (const char *, const struct block *, - const domain_enum, int *); + const domain_enum, + struct field_of_this_result *); /* A default version of lookup_symbol_nonlocal for use by languages that can't think of anything better to do. */ @@ -948,11 +1009,11 @@ extern struct symbol *lookup_block_symbol (const struct block *, const char *, /* lookup a [struct, union, enum] by name, within a specified block. */ -extern struct type *lookup_struct (const char *, struct block *); +extern struct type *lookup_struct (const char *, const struct block *); -extern struct type *lookup_union (const char *, struct block *); +extern struct type *lookup_union (const char *, const struct block *); -extern struct type *lookup_enum (const char *, struct block *); +extern struct type *lookup_enum (const char *, const struct block *); /* from blockframe.c: */ @@ -964,14 +1025,14 @@ extern struct symbol *find_pc_function (CORE_ADDR); extern struct symbol *find_pc_sect_function (CORE_ADDR, struct obj_section *); -extern int find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, char **name, +extern int find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, const char **name, CORE_ADDR *address, CORE_ADDR *endaddr, int *is_gnu_ifunc_p); /* lookup function from address, return name, start addr and end addr. */ -extern int find_pc_partial_function (CORE_ADDR, char **, CORE_ADDR *, +extern int find_pc_partial_function (CORE_ADDR, const char **, CORE_ADDR *, CORE_ADDR *); extern void clear_pc_function_cache (void); @@ -1007,62 +1068,6 @@ extern struct type *basic_lookup_transparent_type (const char *); #define GCC2_COMPILED_FLAG_SYMBOL "gcc2_compiled." #endif -/* Functions for dealing with the minimal symbol table, really a misc - address<->symbol mapping for things we don't have debug symbols for. */ - -extern void prim_record_minimal_symbol (const char *, CORE_ADDR, - enum minimal_symbol_type, - struct objfile *); - -extern struct minimal_symbol *prim_record_minimal_symbol_full - (const char *, int, int, CORE_ADDR, - enum minimal_symbol_type, - int section, asection * bfd_section, struct objfile *); - -extern struct minimal_symbol *prim_record_minimal_symbol_and_info - (const char *, CORE_ADDR, - enum minimal_symbol_type, - int section, asection * bfd_section, struct objfile *); - -extern unsigned int msymbol_hash_iw (const char *); - -extern unsigned int msymbol_hash (const char *); - -/* Compute the next hash value from previous HASH and the character C. This - is only a GDB in-memory computed value with no external files compatibility - requirements. */ - -#define SYMBOL_HASH_NEXT(hash, c) \ - ((hash) * 67 + tolower ((unsigned char) (c)) - 113) - -extern struct objfile * msymbol_objfile (struct minimal_symbol *sym); - -extern void -add_minsym_to_hash_table (struct minimal_symbol *sym, - struct minimal_symbol **table); - -extern struct minimal_symbol *lookup_minimal_symbol (const char *, - const char *, - struct objfile *); - -extern struct minimal_symbol *lookup_minimal_symbol_text (const char *, - struct objfile *); - -struct minimal_symbol *lookup_minimal_symbol_solib_trampoline (const char *, - struct objfile - *); - -extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name - (CORE_ADDR, const char *, struct objfile *); - -extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR); - -extern void iterate_over_minimal_symbols (struct objfile *objf, - const char *name, - void (*callback) (struct minimal_symbol *, - void *), - void *user_data); - extern int in_gnu_ifunc_stub (CORE_ADDR pc); /* Functions for resolving STT_GNU_IFUNC symbols which are implemented only @@ -1092,28 +1097,8 @@ struct gnu_ifunc_fns extern const struct gnu_ifunc_fns *gnu_ifunc_fns_p; -extern struct minimal_symbol * - lookup_minimal_symbol_and_objfile (const char *, - struct objfile **); - -extern struct minimal_symbol - *lookup_minimal_symbol_by_pc_section (CORE_ADDR, struct obj_section *); - -extern struct minimal_symbol - *lookup_solib_trampoline_symbol_by_pc (CORE_ADDR); - extern CORE_ADDR find_solib_trampoline_target (struct frame_info *, CORE_ADDR); -extern void init_minimal_symbol_collection (void); - -extern struct cleanup *make_cleanup_discard_minimal_symbols (void); - -extern void install_minimal_symbols (struct objfile *); - -/* Sort all the minimal symbols in OBJFILE. */ - -extern void msymbols_sort (struct objfile *objfile); - struct symtab_and_line { /* The program space of this sal. */ @@ -1130,6 +1115,9 @@ struct symtab_and_line CORE_ADDR end; int explicit_pc; int explicit_line; + + /* The probe associated with this symtab_and_line. */ + struct probe *probe; }; extern void init_sal (struct symtab_and_line *sal); @@ -1141,21 +1129,6 @@ struct symtabs_and_lines }; - -/* Some types and macros needed for exception catchpoints. - Can't put these in target.h because symtab_and_line isn't - known there. This file will be included by breakpoint.c, - hppa-tdep.c, etc. */ - -/* Enums for exception-handling support. */ -enum exception_event_kind -{ - EX_EVENT_THROW, - EX_EVENT_CATCH -}; - - - /* Given a pc value, return line number it is in. Second arg nonzero means if pc is on the boundary use the previous statement's line number. */ @@ -1175,33 +1148,6 @@ extern int find_line_pc_range (struct symtab_and_line, CORE_ADDR *, extern void resolve_sal_pc (struct symtab_and_line *); -/* Given a string, return the line specified by it. For commands like "list" - and "breakpoint". */ - -extern struct symtabs_and_lines decode_line_spec (char *, int); - -extern struct symtabs_and_lines decode_line_spec_1 (char *, int); - -/* Symmisc.c */ - -void maintenance_print_symbols (char *, int); - -void maintenance_print_psymbols (char *, int); - -void maintenance_print_msymbols (char *, int); - -void maintenance_print_objfiles (char *, int); - -void maintenance_info_symtabs (char *, int); - -void maintenance_info_psymtabs (char *, int); - -void maintenance_check_symtabs (char *, int); - -/* maint.c */ - -void maintenance_print_statistics (char *, int); - /* Symbol-reading stuff in symfile.c and solib.c. */ extern void clear_solib (void); @@ -1210,23 +1156,40 @@ extern void clear_solib (void); extern int identify_source_line (struct symtab *, int, int, CORE_ADDR); -extern void print_source_lines (struct symtab *, int, int, int); +/* Flags passed as 4th argument to print_source_lines. */ + +enum print_source_lines_flags + { + /* Do not print an error message. */ + PRINT_SOURCE_LINES_NOERROR = (1 << 0), + + /* Print the filename in front of the source lines. */ + PRINT_SOURCE_LINES_FILENAME = (1 << 1) + }; + +extern void print_source_lines (struct symtab *, int, int, + enum print_source_lines_flags); extern void forget_cached_source_info_for_objfile (struct objfile *); extern void forget_cached_source_info (void); extern void select_source_symtab (struct symtab *); -extern char **default_make_symbol_completion_list_break_on - (char *text, char *word, const char *break_on); -extern char **default_make_symbol_completion_list (char *, char *); -extern char **make_symbol_completion_list (char *, char *); -extern char **make_symbol_completion_list_fn (struct cmd_list_element *, - char *, char *); +extern VEC (char_ptr) *default_make_symbol_completion_list_break_on + (char *text, char *word, const char *break_on, + enum type_code code); +extern VEC (char_ptr) *default_make_symbol_completion_list (char *, char *, + enum type_code); +extern VEC (char_ptr) *make_symbol_completion_list (char *, char *); +extern VEC (char_ptr) *make_symbol_completion_type (char *, char *, + enum type_code); +extern VEC (char_ptr) *make_symbol_completion_list_fn (struct cmd_list_element *, + char *, char *); -extern char **make_file_symbol_completion_list (char *, char *, char *); +extern VEC (char_ptr) *make_file_symbol_completion_list (char *, + char *, char *); -extern char **make_source_files_completion_list (char *, char *); +extern VEC (char_ptr) *make_source_files_completion_list (char *, char *); /* symtab.c */ @@ -1259,6 +1222,8 @@ extern struct symbol *fixup_symbol_section (struct symbol *, struct objfile *); /* Symbol searching */ +/* Note: struct symbol_search, search_symbols, et.al. are declared here, + instead of making them local to symtab.c, for gdbtk's sake. */ /* When using search_symbols, a list of the following structs is returned. Callers must free the search list using free_search_symbols! */ @@ -1311,10 +1276,14 @@ void fixup_section (struct general_symbol_info *ginfo, struct objfile *lookup_objfile_from_block (const struct block *block); +extern int symtab_create_debug; + extern int basenames_may_differ; +int compare_filenames_for_search (const char *filename, + const char *search_name); + int iterate_over_some_symtabs (const char *name, - const char *full_path, const char *real_path, int (*callback) (struct symtab *symtab, void *data), @@ -1332,9 +1301,18 @@ DEF_VEC_I (CORE_ADDR); VEC (CORE_ADDR) *find_pcs_for_symtab_line (struct symtab *symtab, int line, struct linetable_entry **best_entry); +/* Callback for LA_ITERATE_OVER_SYMBOLS. The callback will be called + once per matching symbol SYM, with DATA being the argument of the + same name that was passed to LA_ITERATE_OVER_SYMBOLS. The callback + should return nonzero to indicate that LA_ITERATE_OVER_SYMBOLS + should continue iterating, or zero to indicate that the iteration + should end. */ + +typedef int (symbol_found_callback_ftype) (struct symbol *sym, void *data); + void iterate_over_symbols (const struct block *block, const char *name, const domain_enum domain, - int (*callback) (struct symbol *, void *), + symbol_found_callback_ftype *callback, void *data); struct cleanup *demangle_for_lookup (const char *name, enum language lang, diff --git a/contrib/gdb-7/gdb/syscalls/gdb-syscalls.dtd b/contrib/gdb-7/gdb/syscalls/gdb-syscalls.dtd index 63a1339e08..05c1ccf897 100644 --- a/contrib/gdb-7/gdb/syscalls/gdb-syscalls.dtd +++ b/contrib/gdb-7/gdb/syscalls/gdb-syscalls.dtd @@ -1,4 +1,4 @@ -